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 (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
2121                 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
2122                     rt_to_str(RT_SECFLAGS));
2123                 export_prop(of, PT_DEFAULT, secflagstab.zone_secflags_default);
2124                 export_prop(of, PT_LOWER, secflagstab.zone_secflags_lower);
2125                 export_prop(of, PT_UPPER, secflagstab.zone_secflags_upper);
2126                 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
2127         }
2128 
2129         /*
2130          * There is nothing to export for pcap since this resource is just
2131          * a container for an rctl alias.
2132          */
2133 
2134 done:
2135         if (need_to_close)
2136                 (void) fclose(of);
2137 }
2138 
2139 void
2140 exit_func(cmd_t *cmd)
2141 {
2142         int arg, answer;
2143         boolean_t arg_err = B_FALSE;
2144 
2145         optind = 0;
2146         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2147                 switch (arg) {
2148                 case '?':
2149                         longer_usage(CMD_EXIT);
2150                         arg_err = B_TRUE;
2151                         break;
2152                 case 'F':
2153                         force_exit = B_TRUE;
2154                         break;
2155                 default:
2156                         short_usage(CMD_EXIT);
2157                         arg_err = B_TRUE;
2158                         break;
2159                 }
2160         }
2161         if (arg_err)
2162                 return;
2163 
2164         if (optind < cmd->cmd_argc) {
2165                 short_usage(CMD_EXIT);
2166                 return;
2167         }
2168 
2169         if (global_scope || force_exit) {
2170                 time_to_exit = B_TRUE;
2171                 return;
2172         }
2173 
2174         answer = ask_yesno(B_FALSE, "Resource incomplete; really quit");
2175         if (answer == -1) {
2176                 zerr(gettext("Resource incomplete, input "
2177                     "not from terminal and -F not specified:\n%s command "
2178                     "ignored, but exiting anyway."), cmd_to_str(CMD_EXIT));
2179                 exit(Z_ERR);
2180         } else if (answer == 1) {
2181                 time_to_exit = B_TRUE;
2182         }
2183         /* (answer == 0) => just return */
2184 }
2185 
2186 static int
2187 validate_zonepath_syntax(char *path)
2188 {
2189         if (path[0] != '/') {
2190                 zerr(gettext("%s is not an absolute path."), path);
2191                 return (Z_ERR);
2192         }
2193         /* If path is all slashes, then fail */
2194         if (strspn(path, "/") == strlen(path)) {
2195                 zerr(gettext("/ is not allowed as a %s."),
2196                     pt_to_str(PT_ZONEPATH));
2197                 return (Z_ERR);
2198         }
2199         return (Z_OK);
2200 }
2201 
2202 static void
2203 add_resource(cmd_t *cmd)
2204 {
2205         int type;
2206         struct zone_psettab tmp_psettab;
2207         struct zone_mcaptab tmp_mcaptab;
2208         struct zone_secflagstab tmp_secflagstab;
2209         uint64_t tmp;
2210         uint64_t tmp_mcap;
2211         char pool[MAXNAMELEN];
2212 
2213         if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
2214                 long_usage(CMD_ADD, B_TRUE);
2215                 goto bad;
2216         }
2217 
2218         switch (type) {
2219         case RT_FS:
2220                 bzero(&in_progress_fstab, sizeof (in_progress_fstab));
2221                 return;
2222         case RT_NET:
2223                 bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
2224                 return;
2225         case RT_DEVICE:
2226                 bzero(&in_progress_devtab, sizeof (in_progress_devtab));
2227                 return;
2228         case RT_RCTL:
2229                 if (global_zone)
2230                         zerr(gettext("WARNING: Setting a global zone resource "
2231                             "control too low could deny\nservice "
2232                             "to even the root user; "
2233                             "this could render the system impossible\n"
2234                             "to administer.  Please use caution."));
2235                 bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
2236                 return;
2237         case RT_ATTR:
2238                 bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
2239                 return;
2240         case RT_DATASET:
2241                 bzero(&in_progress_dstab, sizeof (in_progress_dstab));
2242                 return;
2243         case RT_DCPU:
2244                 /* Make sure there isn't already a cpu-set or cpu-cap entry. */
2245                 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2246                         zerr(gettext("The %s resource already exists."),
2247                             rt_to_str(RT_DCPU));
2248                         goto bad;
2249                 }
2250                 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) !=
2251                     Z_NO_ENTRY) {
2252                         zerr(gettext("The %s resource already exists."),
2253                             rt_to_str(RT_PCAP));
2254                         goto bad;
2255                 }
2256 
2257                 /* Make sure the pool property isn't set. */
2258                 if (zonecfg_get_pool(handle, pool, sizeof (pool)) == Z_OK &&
2259                     strlen(pool) > 0) {
2260                         zerr(gettext("The %s property is already set.  "
2261                             "A persistent pool is incompatible with\nthe %s "
2262                             "resource."),
2263                             pt_to_str(PT_POOL), rt_to_str(RT_DCPU));
2264                         goto bad;
2265                 }
2266 
2267                 bzero(&in_progress_psettab, sizeof (in_progress_psettab));
2268                 return;
2269         case RT_PCAP:
2270                 /*
2271                  * Make sure there isn't already a cpu-set or incompatible
2272                  * cpu-cap rctls.
2273                  */
2274                 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
2275                         zerr(gettext("The %s resource already exists."),
2276                             rt_to_str(RT_DCPU));
2277                         goto bad;
2278                 }
2279 
2280                 switch (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp)) {
2281                 case Z_ALIAS_DISALLOW:
2282                         zone_perror(rt_to_str(RT_PCAP), Z_ALIAS_DISALLOW,
2283                             B_FALSE);
2284                         goto bad;
2285 
2286                 case Z_OK:
2287                         zerr(gettext("The %s resource already exists."),
2288                             rt_to_str(RT_PCAP));
2289                         goto bad;
2290 
2291                 default:
2292                         break;
2293                 }
2294                 return;
2295         case RT_MCAP:
2296                 /*
2297                  * Make sure there isn't already a mem-cap entry or max-swap
2298                  * or max-locked rctl.
2299                  */
2300                 if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
2301                     zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
2302                     == Z_OK ||
2303                     zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
2304                     &tmp_mcap) == Z_OK) {
2305                         zerr(gettext("The %s resource or a related resource "
2306                             "control already exists."), rt_to_str(RT_MCAP));
2307                         goto bad;
2308                 }
2309                 if (global_zone)
2310                         zerr(gettext("WARNING: Setting a global zone memory "
2311                             "cap too low could deny\nservice "
2312                             "to even the root user; "
2313                             "this could render the system impossible\n"
2314                             "to administer.  Please use caution."));
2315                 bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
2316                 return;
2317         case RT_ADMIN:
2318                 bzero(&in_progress_admintab, sizeof (in_progress_admintab));
2319                 return;
2320         case RT_SECFLAGS:
2321                 /* Make sure we haven't already set this */
2322                 if (zonecfg_lookup_secflags(handle, &tmp_secflagstab) == Z_OK)
2323                         zerr(gettext("The %s resource already exists."),
2324                             rt_to_str(RT_SECFLAGS));
2325                 bzero(&in_progress_secflagstab,
2326                     sizeof (in_progress_secflagstab));
2327                 return;
2328         default:
2329                 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
2330                 long_usage(CMD_ADD, B_TRUE);
2331                 usage(B_FALSE, HELP_RESOURCES);
2332         }
2333 bad:
2334         global_scope = B_TRUE;
2335         end_op = -1;
2336 }
2337 
2338 static void
2339 do_complex_rctl_val(complex_property_ptr_t cp)
2340 {
2341         struct zone_rctlvaltab *rctlvaltab;
2342         complex_property_ptr_t cx;
2343         boolean_t seen_priv = B_FALSE, seen_limit = B_FALSE,
2344             seen_action = B_FALSE;
2345         rctlblk_t *rctlblk;
2346         int err;
2347 
2348         if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
2349                 zone_perror(zone, Z_NOMEM, B_TRUE);
2350                 exit(Z_ERR);
2351         }
2352         for (cx = cp; cx != NULL; cx = cx->cp_next) {
2353                 switch (cx->cp_type) {
2354                 case PT_PRIV:
2355                         if (seen_priv) {
2356                                 zerr(gettext("%s already specified"),
2357                                     pt_to_str(PT_PRIV));
2358                                 goto bad;
2359                         }
2360                         (void) strlcpy(rctlvaltab->zone_rctlval_priv,
2361                             cx->cp_value,
2362                             sizeof (rctlvaltab->zone_rctlval_priv));
2363                         seen_priv = B_TRUE;
2364                         break;
2365                 case PT_LIMIT:
2366                         if (seen_limit) {
2367                                 zerr(gettext("%s already specified"),
2368                                     pt_to_str(PT_LIMIT));
2369                                 goto bad;
2370                         }
2371                         (void) strlcpy(rctlvaltab->zone_rctlval_limit,
2372                             cx->cp_value,
2373                             sizeof (rctlvaltab->zone_rctlval_limit));
2374                         seen_limit = B_TRUE;
2375                         break;
2376                 case PT_ACTION:
2377                         if (seen_action) {
2378                                 zerr(gettext("%s already specified"),
2379                                     pt_to_str(PT_ACTION));
2380                                 goto bad;
2381                         }
2382                         (void) strlcpy(rctlvaltab->zone_rctlval_action,
2383                             cx->cp_value,
2384                             sizeof (rctlvaltab->zone_rctlval_action));
2385                         seen_action = B_TRUE;
2386                         break;
2387                 default:
2388                         zone_perror(pt_to_str(PT_VALUE),
2389                             Z_NO_PROPERTY_TYPE, B_TRUE);
2390                         long_usage(CMD_ADD, B_TRUE);
2391                         usage(B_FALSE, HELP_PROPS);
2392                         zonecfg_free_rctl_value_list(rctlvaltab);
2393                         return;
2394                 }
2395         }
2396         if (!seen_priv)
2397                 zerr(gettext("%s not specified"), pt_to_str(PT_PRIV));
2398         if (!seen_limit)
2399                 zerr(gettext("%s not specified"), pt_to_str(PT_LIMIT));
2400         if (!seen_action)
2401                 zerr(gettext("%s not specified"), pt_to_str(PT_ACTION));
2402         if (!seen_priv || !seen_limit || !seen_action)
2403                 goto bad;
2404         rctlvaltab->zone_rctlval_next = NULL;
2405         rctlblk = alloca(rctlblk_size());
2406         /*
2407          * Make sure the rctl value looks roughly correct; we won't know if
2408          * it's truly OK until we verify the configuration on the target
2409          * system.
2410          */
2411         if (zonecfg_construct_rctlblk(rctlvaltab, rctlblk) != Z_OK ||
2412             !zonecfg_valid_rctlblk(rctlblk)) {
2413                 zerr(gettext("Invalid %s %s specification"), rt_to_str(RT_RCTL),
2414                     pt_to_str(PT_VALUE));
2415                 goto bad;
2416         }
2417         err = zonecfg_add_rctl_value(&in_progress_rctltab, rctlvaltab);
2418         if (err != Z_OK)
2419                 zone_perror(pt_to_str(PT_VALUE), err, B_TRUE);
2420         return;
2421 
2422 bad:
2423         zonecfg_free_rctl_value_list(rctlvaltab);
2424 }
2425 
2426 static void
2427 add_property(cmd_t *cmd)
2428 {
2429         char *prop_id;
2430         int err, res_type, prop_type;
2431         property_value_ptr_t pp;
2432         list_property_ptr_t l;
2433 
2434         res_type = resource_scope;
2435         prop_type = cmd->cmd_prop_name[0];
2436         if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
2437                 long_usage(CMD_ADD, B_TRUE);
2438                 return;
2439         }
2440 
2441         if (cmd->cmd_prop_nv_pairs != 1) {
2442                 long_usage(CMD_ADD, B_TRUE);
2443                 return;
2444         }
2445 
2446         if (initialize(B_TRUE) != Z_OK)
2447                 return;
2448 
2449         switch (res_type) {
2450         case RT_FS:
2451                 if (prop_type != PT_OPTIONS) {
2452                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2453                             B_TRUE);
2454                         long_usage(CMD_ADD, B_TRUE);
2455                         usage(B_FALSE, HELP_PROPS);
2456                         return;
2457                 }
2458                 pp = cmd->cmd_property_ptr[0];
2459                 if (pp->pv_type != PROP_VAL_SIMPLE &&
2460                     pp->pv_type != PROP_VAL_LIST) {
2461                         zerr(gettext("A %s or %s value was expected here."),
2462                             pvt_to_str(PROP_VAL_SIMPLE),
2463                             pvt_to_str(PROP_VAL_LIST));
2464                         saw_error = B_TRUE;
2465                         return;
2466                 }
2467                 if (pp->pv_type == PROP_VAL_SIMPLE) {
2468                         if (pp->pv_simple == NULL) {
2469                                 long_usage(CMD_ADD, B_TRUE);
2470                                 return;
2471                         }
2472                         prop_id = pp->pv_simple;
2473                         err = zonecfg_add_fs_option(&in_progress_fstab,
2474                             prop_id);
2475                         if (err != Z_OK)
2476                                 zone_perror(pt_to_str(prop_type), err, B_TRUE);
2477                 } else {
2478                         list_property_ptr_t list;
2479 
2480                         for (list = pp->pv_list; list != NULL;
2481                             list = list->lp_next) {
2482                                 prop_id = list->lp_simple;
2483                                 if (prop_id == NULL)
2484                                         break;
2485                                 err = zonecfg_add_fs_option(
2486                                     &in_progress_fstab, prop_id);
2487                                 if (err != Z_OK)
2488                                         zone_perror(pt_to_str(prop_type), err,
2489                                             B_TRUE);
2490                         }
2491                 }
2492                 return;
2493         case RT_RCTL:
2494                 if (prop_type != PT_VALUE) {
2495                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
2496                             B_TRUE);
2497                         long_usage(CMD_ADD, B_TRUE);
2498                         usage(B_FALSE, HELP_PROPS);
2499                         return;
2500                 }
2501                 pp = cmd->cmd_property_ptr[0];
2502                 if (pp->pv_type != PROP_VAL_COMPLEX &&
2503                     pp->pv_type != PROP_VAL_LIST) {
2504                         zerr(gettext("A %s or %s value was expected here."),
2505                             pvt_to_str(PROP_VAL_COMPLEX),
2506                             pvt_to_str(PROP_VAL_LIST));
2507                         saw_error = B_TRUE;
2508                         return;
2509                 }
2510                 if (pp->pv_type == PROP_VAL_COMPLEX) {
2511                         do_complex_rctl_val(pp->pv_complex);
2512                         return;
2513                 }
2514                 for (l = pp->pv_list; l != NULL; l = l->lp_next)
2515                         do_complex_rctl_val(l->lp_complex);
2516                 return;
2517         default:
2518                 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
2519                 long_usage(CMD_ADD, B_TRUE);
2520                 usage(B_FALSE, HELP_RESOURCES);
2521                 return;
2522         }
2523 }
2524 
2525 static boolean_t
2526 gz_invalid_resource(int type)
2527 {
2528         return (global_zone && (type == RT_FS ||
2529             type == RT_NET || type == RT_DEVICE || type == RT_ATTR ||
2530             type == RT_DATASET));
2531 }
2532 
2533 static boolean_t
2534 gz_invalid_rt_property(int type)
2535 {
2536         return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
2537             type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
2538             type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
2539             type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
2540 }
2541 
2542 static boolean_t
2543 gz_invalid_property(int type)
2544 {
2545         return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
2546             type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
2547             type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
2548             type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
2549 }
2550 
2551 void
2552 add_func(cmd_t *cmd)
2553 {
2554         int arg;
2555         boolean_t arg_err = B_FALSE;
2556 
2557         assert(cmd != NULL);
2558 
2559         optind = 0;
2560         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
2561                 switch (arg) {
2562                 case '?':
2563                         longer_usage(CMD_ADD);
2564                         arg_err = B_TRUE;
2565                         break;
2566                 default:
2567                         short_usage(CMD_ADD);
2568                         arg_err = B_TRUE;
2569                         break;
2570                 }
2571         }
2572         if (arg_err)
2573                 return;
2574 
2575         if (optind != cmd->cmd_argc) {
2576                 short_usage(CMD_ADD);
2577                 return;
2578         }
2579 
2580         if (zone_is_read_only(CMD_ADD))
2581                 return;
2582 
2583         if (initialize(B_TRUE) != Z_OK)
2584                 return;
2585         if (global_scope) {
2586                 if (gz_invalid_resource(cmd->cmd_res_type)) {
2587                         zerr(gettext("Cannot add a %s resource to the "
2588                             "global zone."), rt_to_str(cmd->cmd_res_type));
2589                         saw_error = B_TRUE;
2590                         return;
2591                 }
2592 
2593                 global_scope = B_FALSE;
2594                 resource_scope = cmd->cmd_res_type;
2595                 end_op = CMD_ADD;
2596                 add_resource(cmd);
2597         } else
2598                 add_property(cmd);
2599 }
2600 
2601 /*
2602  * This routine has an unusual implementation, because it tries very
2603  * hard to succeed in the face of a variety of failure modes.
2604  * The most common and most vexing occurs when the index file and
2605  * the /etc/zones/<zonename.xml> file are not both present.  In
2606  * this case, delete must eradicate as much of the zone state as is left
2607  * so that the user can later create a new zone with the same name.
2608  */
2609 void
2610 delete_func(cmd_t *cmd)
2611 {
2612         int err, arg, answer;
2613         char line[ZONENAME_MAX + 128];  /* enough to ask a question */
2614         boolean_t force = B_FALSE;
2615         boolean_t arg_err = B_FALSE;
2616 
2617         optind = 0;
2618         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
2619                 switch (arg) {
2620                 case '?':
2621                         longer_usage(CMD_DELETE);
2622                         arg_err = B_TRUE;
2623                         break;
2624                 case 'F':
2625                         force = B_TRUE;
2626                         break;
2627                 default:
2628                         short_usage(CMD_DELETE);
2629                         arg_err = B_TRUE;
2630                         break;
2631                 }
2632         }
2633         if (arg_err)
2634                 return;
2635 
2636         if (optind != cmd->cmd_argc) {
2637                 short_usage(CMD_DELETE);
2638                 return;
2639         }
2640 
2641         if (zone_is_read_only(CMD_DELETE))
2642                 return;
2643 
2644         if (!force) {
2645                 /*
2646                  * Initialize sets up the global called "handle" and warns the
2647                  * user if the zone is not configured.  In force mode, we don't
2648                  * trust that evaluation, and hence skip it.  (We don't need the
2649                  * handle to be loaded anyway, since zonecfg_destroy is done by
2650                  * zonename). However, we also have to take care to emulate the
2651                  * messages spit out by initialize; see below.
2652                  */
2653                 if (initialize(B_TRUE) != Z_OK)
2654                         return;
2655 
2656                 (void) snprintf(line, sizeof (line),
2657                     gettext("Are you sure you want to delete zone %s"), zone);
2658                 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
2659                         zerr(gettext("Input not from terminal and -F not "
2660                             "specified:\n%s command ignored, exiting."),
2661                             cmd_to_str(CMD_DELETE));
2662                         exit(Z_ERR);
2663                 }
2664                 if (answer != 1)
2665                         return;
2666         }
2667 
2668         /*
2669          * This function removes the authorizations from user_attr
2670          * that correspond to those specified in the configuration
2671          */
2672         if (initialize(B_TRUE) == Z_OK) {
2673                 (void) zonecfg_deauthorize_users(handle, zone);
2674         }
2675         if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
2676                 if ((err == Z_BAD_ZONE_STATE) && !force) {
2677                         zerr(gettext("Zone %s not in %s state; %s not "
2678                             "allowed.  Use -F to force %s."),
2679                             zone, zone_state_str(ZONE_STATE_CONFIGURED),
2680                             cmd_to_str(CMD_DELETE), cmd_to_str(CMD_DELETE));
2681                 } else {
2682                         zone_perror(zone, err, B_TRUE);
2683                 }
2684         }
2685         need_to_commit = B_FALSE;
2686 
2687         /*
2688          * Emulate initialize's messaging; if there wasn't a valid handle to
2689          * begin with, then user had typed delete (or delete -F) multiple
2690          * times.  So we emit a message.
2691          *
2692          * We only do this in the 'force' case because normally, initialize()
2693          * takes care of this for us.
2694          */
2695         if (force && zonecfg_check_handle(handle) != Z_OK && interactive_mode)
2696                 (void) printf(gettext("Use '%s' to begin "
2697                     "configuring a new zone.\n"), cmd_to_str(CMD_CREATE));
2698 
2699         /*
2700          * Time for a new handle: finish the old one off first
2701          * then get a new one properly to avoid leaks.
2702          */
2703         if (got_handle) {
2704                 zonecfg_fini_handle(handle);
2705                 if ((handle = zonecfg_init_handle()) == NULL) {
2706                         zone_perror(execname, Z_NOMEM, B_TRUE);
2707                         exit(Z_ERR);
2708                 }
2709                 if ((err = zonecfg_get_handle(zone, handle)) != Z_OK) {
2710                         /* If there was no zone before, that's OK */
2711                         if (err != Z_NO_ZONE)
2712                                 zone_perror(zone, err, B_TRUE);
2713                         got_handle = B_FALSE;
2714                 }
2715         }
2716 }
2717 
2718 static int
2719 fill_in_fstab(cmd_t *cmd, struct zone_fstab *fstab, boolean_t fill_in_only)
2720 {
2721         int err, i;
2722         property_value_ptr_t pp;
2723 
2724         if ((err = initialize(B_TRUE)) != Z_OK)
2725                 return (err);
2726 
2727         bzero(fstab, sizeof (*fstab));
2728         for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2729                 pp = cmd->cmd_property_ptr[i];
2730                 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2731                         zerr(gettext("A simple value was expected here."));
2732                         saw_error = B_TRUE;
2733                         return (Z_INSUFFICIENT_SPEC);
2734                 }
2735                 switch (cmd->cmd_prop_name[i]) {
2736                 case PT_DIR:
2737                         (void) strlcpy(fstab->zone_fs_dir, pp->pv_simple,
2738                             sizeof (fstab->zone_fs_dir));
2739                         break;
2740                 case PT_SPECIAL:
2741                         (void) strlcpy(fstab->zone_fs_special, pp->pv_simple,
2742                             sizeof (fstab->zone_fs_special));
2743                         break;
2744                 case PT_RAW:
2745                         (void) strlcpy(fstab->zone_fs_raw, pp->pv_simple,
2746                             sizeof (fstab->zone_fs_raw));
2747                         break;
2748                 case PT_TYPE:
2749                         (void) strlcpy(fstab->zone_fs_type, pp->pv_simple,
2750                             sizeof (fstab->zone_fs_type));
2751                         break;
2752                 default:
2753                         zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2754                             Z_NO_PROPERTY_TYPE, B_TRUE);
2755                         return (Z_INSUFFICIENT_SPEC);
2756                 }
2757         }
2758         if (fill_in_only)
2759                 return (Z_OK);
2760         return (zonecfg_lookup_filesystem(handle, fstab));
2761 }
2762 
2763 static int
2764 fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
2765     boolean_t fill_in_only)
2766 {
2767         int err, i;
2768         property_value_ptr_t pp;
2769 
2770         if ((err = initialize(B_TRUE)) != Z_OK)
2771                 return (err);
2772 
2773         bzero(nwiftab, sizeof (*nwiftab));
2774         for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2775                 pp = cmd->cmd_property_ptr[i];
2776                 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2777                         zerr(gettext("A simple value was expected here."));
2778                         saw_error = B_TRUE;
2779                         return (Z_INSUFFICIENT_SPEC);
2780                 }
2781                 switch (cmd->cmd_prop_name[i]) {
2782                 case PT_ADDRESS:
2783                         (void) strlcpy(nwiftab->zone_nwif_address,
2784                             pp->pv_simple, sizeof (nwiftab->zone_nwif_address));
2785                         break;
2786                 case PT_ALLOWED_ADDRESS:
2787                         (void) strlcpy(nwiftab->zone_nwif_allowed_address,
2788                             pp->pv_simple,
2789                             sizeof (nwiftab->zone_nwif_allowed_address));
2790                         break;
2791                 case PT_PHYSICAL:
2792                         (void) strlcpy(nwiftab->zone_nwif_physical,
2793                             pp->pv_simple,
2794                             sizeof (nwiftab->zone_nwif_physical));
2795                         break;
2796                 case PT_DEFROUTER:
2797                         (void) strlcpy(nwiftab->zone_nwif_defrouter,
2798                             pp->pv_simple,
2799                             sizeof (nwiftab->zone_nwif_defrouter));
2800                         break;
2801                 default:
2802                         zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2803                             Z_NO_PROPERTY_TYPE, B_TRUE);
2804                         return (Z_INSUFFICIENT_SPEC);
2805                 }
2806         }
2807         if (fill_in_only)
2808                 return (Z_OK);
2809         err = zonecfg_lookup_nwif(handle, nwiftab);
2810         return (err);
2811 }
2812 
2813 static int
2814 fill_in_devtab(cmd_t *cmd, struct zone_devtab *devtab, boolean_t fill_in_only)
2815 {
2816         int err, i;
2817         property_value_ptr_t pp;
2818 
2819         if ((err = initialize(B_TRUE)) != Z_OK)
2820                 return (err);
2821 
2822         bzero(devtab, sizeof (*devtab));
2823         for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2824                 pp = cmd->cmd_property_ptr[i];
2825                 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2826                         zerr(gettext("A simple value was expected here."));
2827                         saw_error = B_TRUE;
2828                         return (Z_INSUFFICIENT_SPEC);
2829                 }
2830                 switch (cmd->cmd_prop_name[i]) {
2831                 case PT_MATCH:
2832                         (void) strlcpy(devtab->zone_dev_match, pp->pv_simple,
2833                             sizeof (devtab->zone_dev_match));
2834                         break;
2835                 default:
2836                         zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2837                             Z_NO_PROPERTY_TYPE, B_TRUE);
2838                         return (Z_INSUFFICIENT_SPEC);
2839                 }
2840         }
2841         if (fill_in_only)
2842                 return (Z_OK);
2843         err = zonecfg_lookup_dev(handle, devtab);
2844         return (err);
2845 }
2846 
2847 static int
2848 fill_in_rctltab(cmd_t *cmd, struct zone_rctltab *rctltab,
2849     boolean_t fill_in_only)
2850 {
2851         int err, i;
2852         property_value_ptr_t pp;
2853 
2854         if ((err = initialize(B_TRUE)) != Z_OK)
2855                 return (err);
2856 
2857         bzero(rctltab, sizeof (*rctltab));
2858         for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2859                 pp = cmd->cmd_property_ptr[i];
2860                 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2861                         zerr(gettext("A simple value was expected here."));
2862                         saw_error = B_TRUE;
2863                         return (Z_INSUFFICIENT_SPEC);
2864                 }
2865                 switch (cmd->cmd_prop_name[i]) {
2866                 case PT_NAME:
2867                         (void) strlcpy(rctltab->zone_rctl_name, pp->pv_simple,
2868                             sizeof (rctltab->zone_rctl_name));
2869                         break;
2870                 default:
2871                         zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2872                             Z_NO_PROPERTY_TYPE, B_TRUE);
2873                         return (Z_INSUFFICIENT_SPEC);
2874                 }
2875         }
2876         if (fill_in_only)
2877                 return (Z_OK);
2878         err = zonecfg_lookup_rctl(handle, rctltab);
2879         return (err);
2880 }
2881 
2882 static int
2883 fill_in_attrtab(cmd_t *cmd, struct zone_attrtab *attrtab,
2884     boolean_t fill_in_only)
2885 {
2886         int err, i;
2887         property_value_ptr_t pp;
2888 
2889         if ((err = initialize(B_TRUE)) != Z_OK)
2890                 return (err);
2891 
2892         bzero(attrtab, sizeof (*attrtab));
2893         for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2894                 pp = cmd->cmd_property_ptr[i];
2895                 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2896                         zerr(gettext("A simple value was expected here."));
2897                         saw_error = B_TRUE;
2898                         return (Z_INSUFFICIENT_SPEC);
2899                 }
2900                 switch (cmd->cmd_prop_name[i]) {
2901                 case PT_NAME:
2902                         (void) strlcpy(attrtab->zone_attr_name, pp->pv_simple,
2903                             sizeof (attrtab->zone_attr_name));
2904                         break;
2905                 case PT_TYPE:
2906                         (void) strlcpy(attrtab->zone_attr_type, pp->pv_simple,
2907                             sizeof (attrtab->zone_attr_type));
2908                         break;
2909                 case PT_VALUE:
2910                         (void) strlcpy(attrtab->zone_attr_value, pp->pv_simple,
2911                             sizeof (attrtab->zone_attr_value));
2912                         break;
2913                 default:
2914                         zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2915                             Z_NO_PROPERTY_TYPE, B_TRUE);
2916                         return (Z_INSUFFICIENT_SPEC);
2917                 }
2918         }
2919         if (fill_in_only)
2920                 return (Z_OK);
2921         err = zonecfg_lookup_attr(handle, attrtab);
2922         return (err);
2923 }
2924 
2925 static int
2926 fill_in_dstab(cmd_t *cmd, struct zone_dstab *dstab, boolean_t fill_in_only)
2927 {
2928         int err, i;
2929         property_value_ptr_t pp;
2930 
2931         if ((err = initialize(B_TRUE)) != Z_OK)
2932                 return (err);
2933 
2934         dstab->zone_dataset_name[0] = '\0';
2935         for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2936                 pp = cmd->cmd_property_ptr[i];
2937                 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2938                         zerr(gettext("A simple value was expected here."));
2939                         saw_error = B_TRUE;
2940                         return (Z_INSUFFICIENT_SPEC);
2941                 }
2942                 switch (cmd->cmd_prop_name[i]) {
2943                 case PT_NAME:
2944                         (void) strlcpy(dstab->zone_dataset_name, pp->pv_simple,
2945                             sizeof (dstab->zone_dataset_name));
2946                         break;
2947                 default:
2948                         zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2949                             Z_NO_PROPERTY_TYPE, B_TRUE);
2950                         return (Z_INSUFFICIENT_SPEC);
2951                 }
2952         }
2953         if (fill_in_only)
2954                 return (Z_OK);
2955         return (zonecfg_lookup_ds(handle, dstab));
2956 }
2957 
2958 static int
2959 fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab,
2960     boolean_t fill_in_only)
2961 {
2962         int err, i;
2963         property_value_ptr_t pp;
2964 
2965         if ((err = initialize(B_TRUE)) != Z_OK)
2966                 return (err);
2967 
2968         bzero(admintab, sizeof (*admintab));
2969         for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
2970                 pp = cmd->cmd_property_ptr[i];
2971                 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
2972                         zerr(gettext("A simple value was expected here."));
2973                         saw_error = B_TRUE;
2974                         return (Z_INSUFFICIENT_SPEC);
2975                 }
2976                 switch (cmd->cmd_prop_name[i]) {
2977                 case PT_USER:
2978                         (void) strlcpy(admintab->zone_admin_user, pp->pv_simple,
2979                             sizeof (admintab->zone_admin_user));
2980                         break;
2981                 case PT_AUTHS:
2982                         (void) strlcpy(admintab->zone_admin_auths,
2983                             pp->pv_simple, sizeof (admintab->zone_admin_auths));
2984                         break;
2985                 default:
2986                         zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
2987                             Z_NO_PROPERTY_TYPE, B_TRUE);
2988                         return (Z_INSUFFICIENT_SPEC);
2989                 }
2990         }
2991         if (fill_in_only)
2992                 return (Z_OK);
2993         err = zonecfg_lookup_admin(handle, admintab);
2994         return (err);
2995 }
2996 
2997 static int
2998 fill_in_secflagstab(cmd_t *cmd, struct zone_secflagstab *secflagstab,
2999     boolean_t fill_in_only)
3000 {
3001         int err, i;
3002         property_value_ptr_t pp;
3003 
3004         if ((err = initialize(B_TRUE)) != Z_OK)
3005                 return (err);
3006 
3007         bzero(secflagstab, sizeof (*secflagstab));
3008         for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
3009                 pp = cmd->cmd_property_ptr[i];
3010                 if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
3011                         zerr(gettext("A simple value was expected here."));
3012                         saw_error = B_TRUE;
3013                         return (Z_INSUFFICIENT_SPEC);
3014                 }
3015                 switch (cmd->cmd_prop_name[i]) {
3016                 case PT_DEFAULT:
3017                         (void) strlcpy(secflagstab->zone_secflags_default,
3018                             pp->pv_simple,
3019                             sizeof (secflagstab->zone_secflags_default));
3020                         break;
3021                 case PT_LOWER:
3022                         (void) strlcpy(secflagstab->zone_secflags_lower,
3023                             pp->pv_simple,
3024                             sizeof (secflagstab->zone_secflags_lower));
3025                         break;
3026                 case PT_UPPER:
3027                         (void) strlcpy(secflagstab->zone_secflags_upper,
3028                             pp->pv_simple,
3029                             sizeof (secflagstab->zone_secflags_upper));
3030                         break;
3031                 default:
3032                         zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
3033                             Z_NO_PROPERTY_TYPE, B_TRUE);
3034                         return (Z_INSUFFICIENT_SPEC);
3035                 }
3036         }
3037         if (fill_in_only)
3038                 return (Z_OK);
3039 
3040         err = zonecfg_lookup_secflags(handle, secflagstab);
3041 
3042         return (err);
3043 }
3044 
3045 static void
3046 remove_aliased_rctl(int type, char *name)
3047 {
3048         int err;
3049         uint64_t tmp;
3050 
3051         if ((err = zonecfg_get_aliased_rctl(handle, name, &tmp)) != Z_OK) {
3052                 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3053                     zonecfg_strerror(err));
3054                 saw_error = B_TRUE;
3055                 return;
3056         }
3057         if ((err = zonecfg_rm_aliased_rctl(handle, name)) != Z_OK) {
3058                 zerr("%s %s: %s", cmd_to_str(CMD_CLEAR), pt_to_str(type),
3059                     zonecfg_strerror(err));
3060                 saw_error = B_TRUE;
3061         } else {
3062                 need_to_commit = B_TRUE;
3063         }
3064 }
3065 
3066 static boolean_t
3067 prompt_remove_resource(cmd_t *cmd, char *rsrc)
3068 {
3069         int num;
3070         int answer;
3071         int arg;
3072         boolean_t force = B_FALSE;
3073         char prompt[128];
3074         boolean_t arg_err = B_FALSE;
3075 
3076         optind = 0;
3077         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
3078                 switch (arg) {
3079                 case 'F':
3080                         force = B_TRUE;
3081                         break;
3082                 default:
3083                         arg_err = B_TRUE;
3084                         break;
3085                 }
3086         }
3087         if (arg_err)
3088                 return (B_FALSE);
3089 
3090 
3091         num = zonecfg_num_resources(handle, rsrc);
3092 
3093         if (num == 0) {
3094                 z_cmd_rt_perror(CMD_REMOVE, cmd->cmd_res_type, Z_NO_ENTRY,
3095                     B_TRUE);
3096                 return (B_FALSE);
3097         }
3098         if (num > 1 && !force) {
3099                 if (!interactive_mode) {
3100                         zerr(gettext("There are multiple instances of this "
3101                             "resource.  Either qualify the resource to\n"
3102                             "remove a single instance or use the -F option to "
3103                             "remove all instances."));
3104                         saw_error = B_TRUE;
3105                         return (B_FALSE);
3106                 }
3107                 (void) snprintf(prompt, sizeof (prompt), gettext(
3108                     "Are you sure you want to remove ALL '%s' resources"),
3109                     rsrc);
3110                 answer = ask_yesno(B_FALSE, prompt);
3111                 if (answer == -1) {
3112                         zerr(gettext("Resource incomplete."));
3113                         return (B_FALSE);
3114                 }
3115                 if (answer != 1)
3116                         return (B_FALSE);
3117         }
3118         return (B_TRUE);
3119 }
3120 
3121 static void
3122 remove_fs(cmd_t *cmd)
3123 {
3124         int err;
3125 
3126         /* traditional, qualified fs removal */
3127         if (cmd->cmd_prop_nv_pairs > 0) {
3128                 struct zone_fstab fstab;
3129 
3130                 if ((err = fill_in_fstab(cmd, &fstab, B_FALSE)) != Z_OK) {
3131                         z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3132                         return;
3133                 }
3134                 if ((err = zonecfg_delete_filesystem(handle, &fstab)) != Z_OK)
3135                         z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3136                 else
3137                         need_to_commit = B_TRUE;
3138                 zonecfg_free_fs_option_list(fstab.zone_fs_options);
3139                 return;
3140         }
3141 
3142         /*
3143          * unqualified fs removal.  remove all fs's but prompt if more
3144          * than one.
3145          */
3146         if (!prompt_remove_resource(cmd, "fs"))
3147                 return;
3148 
3149         if ((err = zonecfg_del_all_resources(handle, "fs")) != Z_OK)
3150                 z_cmd_rt_perror(CMD_REMOVE, RT_FS, err, B_TRUE);
3151         else
3152                 need_to_commit = B_TRUE;
3153 }
3154 
3155 static void
3156 remove_net(cmd_t *cmd)
3157 {
3158         int err;
3159 
3160         /* traditional, qualified net removal */
3161         if (cmd->cmd_prop_nv_pairs > 0) {
3162                 struct zone_nwiftab nwiftab;
3163 
3164                 if ((err = fill_in_nwiftab(cmd, &nwiftab, B_FALSE)) != Z_OK) {
3165                         z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3166                         return;
3167                 }
3168                 if ((err = zonecfg_delete_nwif(handle, &nwiftab)) != Z_OK)
3169                         z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3170                 else
3171                         need_to_commit = B_TRUE;
3172                 return;
3173         }
3174 
3175         /*
3176          * unqualified net removal.  remove all nets but prompt if more
3177          * than one.
3178          */
3179         if (!prompt_remove_resource(cmd, "net"))
3180                 return;
3181 
3182         if ((err = zonecfg_del_all_resources(handle, "net")) != Z_OK)
3183                 z_cmd_rt_perror(CMD_REMOVE, RT_NET, err, B_TRUE);
3184         else
3185                 need_to_commit = B_TRUE;
3186 }
3187 
3188 static void
3189 remove_device(cmd_t *cmd)
3190 {
3191         int err;
3192 
3193         /* traditional, qualified device removal */
3194         if (cmd->cmd_prop_nv_pairs > 0) {
3195                 struct zone_devtab devtab;
3196 
3197                 if ((err = fill_in_devtab(cmd, &devtab, B_FALSE)) != Z_OK) {
3198                         z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3199                         return;
3200                 }
3201                 if ((err = zonecfg_delete_dev(handle, &devtab)) != Z_OK)
3202                         z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3203                 else
3204                         need_to_commit = B_TRUE;
3205                 return;
3206         }
3207 
3208         /*
3209          * unqualified device removal.  remove all devices but prompt if more
3210          * than one.
3211          */
3212         if (!prompt_remove_resource(cmd, "device"))
3213                 return;
3214 
3215         if ((err = zonecfg_del_all_resources(handle, "device")) != Z_OK)
3216                 z_cmd_rt_perror(CMD_REMOVE, RT_DEVICE, err, B_TRUE);
3217         else
3218                 need_to_commit = B_TRUE;
3219 }
3220 
3221 static void
3222 remove_attr(cmd_t *cmd)
3223 {
3224         int err;
3225 
3226         /* traditional, qualified attr removal */
3227         if (cmd->cmd_prop_nv_pairs > 0) {
3228                 struct zone_attrtab attrtab;
3229 
3230                 if ((err = fill_in_attrtab(cmd, &attrtab, B_FALSE)) != Z_OK) {
3231                         z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3232                         return;
3233                 }
3234                 if ((err = zonecfg_delete_attr(handle, &attrtab)) != Z_OK)
3235                         z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3236                 else
3237                         need_to_commit = B_TRUE;
3238                 return;
3239         }
3240 
3241         /*
3242          * unqualified attr removal.  remove all attrs but prompt if more
3243          * than one.
3244          */
3245         if (!prompt_remove_resource(cmd, "attr"))
3246                 return;
3247 
3248         if ((err = zonecfg_del_all_resources(handle, "attr")) != Z_OK)
3249                 z_cmd_rt_perror(CMD_REMOVE, RT_ATTR, err, B_TRUE);
3250         else
3251                 need_to_commit = B_TRUE;
3252 }
3253 
3254 static void
3255 remove_dataset(cmd_t *cmd)
3256 {
3257         int err;
3258 
3259         /* traditional, qualified dataset removal */
3260         if (cmd->cmd_prop_nv_pairs > 0) {
3261                 struct zone_dstab dstab;
3262 
3263                 if ((err = fill_in_dstab(cmd, &dstab, B_FALSE)) != Z_OK) {
3264                         z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3265                         return;
3266                 }
3267                 if ((err = zonecfg_delete_ds(handle, &dstab)) != Z_OK)
3268                         z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3269                 else
3270                         need_to_commit = B_TRUE;
3271                 return;
3272         }
3273 
3274         /*
3275          * unqualified dataset removal.  remove all datasets but prompt if more
3276          * than one.
3277          */
3278         if (!prompt_remove_resource(cmd, "dataset"))
3279                 return;
3280 
3281         if ((err = zonecfg_del_all_resources(handle, "dataset")) != Z_OK)
3282                 z_cmd_rt_perror(CMD_REMOVE, RT_DATASET, err, B_TRUE);
3283         else
3284                 need_to_commit = B_TRUE;
3285 }
3286 
3287 static void
3288 remove_rctl(cmd_t *cmd)
3289 {
3290         int err;
3291 
3292         /* traditional, qualified rctl removal */
3293         if (cmd->cmd_prop_nv_pairs > 0) {
3294                 struct zone_rctltab rctltab;
3295 
3296                 if ((err = fill_in_rctltab(cmd, &rctltab, B_FALSE)) != Z_OK) {
3297                         z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3298                         return;
3299                 }
3300                 if ((err = zonecfg_delete_rctl(handle, &rctltab)) != Z_OK)
3301                         z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3302                 else
3303                         need_to_commit = B_TRUE;
3304                 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
3305                 return;
3306         }
3307 
3308         /*
3309          * unqualified rctl removal.  remove all rctls but prompt if more
3310          * than one.
3311          */
3312         if (!prompt_remove_resource(cmd, "rctl"))
3313                 return;
3314 
3315         if ((err = zonecfg_del_all_resources(handle, "rctl")) != Z_OK)
3316                 z_cmd_rt_perror(CMD_REMOVE, RT_RCTL, err, B_TRUE);
3317         else
3318                 need_to_commit = B_TRUE;
3319 }
3320 
3321 static void
3322 remove_pset()
3323 {
3324         int err;
3325         struct zone_psettab psettab;
3326 
3327         if ((err = zonecfg_lookup_pset(handle, &psettab)) != Z_OK) {
3328                 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3329                 return;
3330         }
3331         if ((err = zonecfg_delete_pset(handle)) != Z_OK)
3332                 z_cmd_rt_perror(CMD_REMOVE, RT_DCPU, err, B_TRUE);
3333         else
3334                 need_to_commit = B_TRUE;
3335 }
3336 
3337 static void
3338 remove_pcap()
3339 {
3340         int err;
3341         uint64_t tmp;
3342 
3343         if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp) != Z_OK) {
3344                 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_PCAP),
3345                     zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3346                 saw_error = B_TRUE;
3347                 return;
3348         }
3349 
3350         if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_CPUCAP)) != Z_OK)
3351                 z_cmd_rt_perror(CMD_REMOVE, RT_PCAP, err, B_TRUE);
3352         else
3353                 need_to_commit = B_TRUE;
3354 }
3355 
3356 static void
3357 remove_mcap()
3358 {
3359         int err, res1, res2, res3;
3360         uint64_t tmp;
3361         struct zone_mcaptab mcaptab;
3362         boolean_t revert = B_FALSE;
3363 
3364         res1 = zonecfg_lookup_mcap(handle, &mcaptab);
3365         res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
3366         res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
3367 
3368         /* if none of these exist, there is no resource to remove */
3369         if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
3370                 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE), rt_to_str(RT_MCAP),
3371                     zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3372                 saw_error = B_TRUE;
3373                 return;
3374         }
3375         if (res1 == Z_OK) {
3376                 if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
3377                         z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3378                         revert = B_TRUE;
3379                 } else {
3380                         need_to_commit = B_TRUE;
3381                 }
3382         }
3383         if (res2 == Z_OK) {
3384                 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
3385                     != Z_OK) {
3386                         z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3387                         revert = B_TRUE;
3388                 } else {
3389                         need_to_commit = B_TRUE;
3390                 }
3391         }
3392         if (res3 == Z_OK) {
3393                 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM))
3394                     != Z_OK) {
3395                         z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
3396                         revert = B_TRUE;
3397                 } else {
3398                         need_to_commit = B_TRUE;
3399                 }
3400         }
3401 
3402         if (revert)
3403                 need_to_commit = B_FALSE;
3404 }
3405 
3406 static void
3407 remove_admin(cmd_t *cmd)
3408 {
3409         int err;
3410 
3411         /* traditional, qualified attr removal */
3412         if (cmd->cmd_prop_nv_pairs > 0) {
3413                 struct zone_admintab admintab;
3414 
3415                 if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) {
3416                         z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3417                             err, B_TRUE);
3418                         return;
3419                 }
3420                 if ((err = zonecfg_delete_admin(handle, &admintab,
3421                     zone))
3422                     != Z_OK)
3423                         z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3424                             err, B_TRUE);
3425                 else
3426                         need_to_commit = B_TRUE;
3427                 return;
3428         } else {
3429                 /*
3430                  * unqualified admin removal.
3431                  * remove all admins but prompt if more
3432                  * than one.
3433                  */
3434                 if (!prompt_remove_resource(cmd, "admin"))
3435                         return;
3436 
3437                 if ((err = zonecfg_delete_admins(handle, zone))
3438                     != Z_OK)
3439                         z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
3440                             err, B_TRUE);
3441                 else
3442                         need_to_commit = B_TRUE;
3443         }
3444 }
3445 
3446 static void
3447 remove_secflags()
3448 {
3449         int err;
3450         struct zone_secflagstab sectab = { 0 };
3451 
3452         if (zonecfg_lookup_secflags(handle, &sectab) != Z_OK) {
3453                 zerr("%s %s: %s", cmd_to_str(CMD_REMOVE),
3454                     rt_to_str(RT_SECFLAGS),
3455                     zonecfg_strerror(Z_NO_RESOURCE_TYPE));
3456                 return;
3457         }
3458 
3459         if ((err = zonecfg_delete_secflags(handle, &sectab)) != Z_OK) {
3460                 z_cmd_rt_perror(CMD_REMOVE, RT_SECFLAGS, err, B_TRUE);
3461                 return;
3462         }
3463 
3464         need_to_commit = B_TRUE;
3465 }
3466 
3467 static void
3468 remove_resource(cmd_t *cmd)
3469 {
3470         int type;
3471         int arg;
3472         boolean_t arg_err = B_FALSE;
3473 
3474         if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3475                 long_usage(CMD_REMOVE, B_TRUE);
3476                 return;
3477         }
3478 
3479         optind = 0;
3480         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
3481                 switch (arg) {
3482                 case '?':
3483                         longer_usage(CMD_REMOVE);
3484                         arg_err = B_TRUE;
3485                         break;
3486                 case 'F':
3487                         break;
3488                 default:
3489                         short_usage(CMD_REMOVE);
3490                         arg_err = B_TRUE;
3491                         break;
3492                 }
3493         }
3494         if (arg_err)
3495                 return;
3496 
3497         if (initialize(B_TRUE) != Z_OK)
3498                 return;
3499 
3500         switch (type) {
3501         case RT_FS:
3502                 remove_fs(cmd);
3503                 return;
3504         case RT_NET:
3505                 remove_net(cmd);
3506                 return;
3507         case RT_DEVICE:
3508                 remove_device(cmd);
3509                 return;
3510         case RT_RCTL:
3511                 remove_rctl(cmd);
3512                 return;
3513         case RT_ATTR:
3514                 remove_attr(cmd);
3515                 return;
3516         case RT_DATASET:
3517                 remove_dataset(cmd);
3518                 return;
3519         case RT_DCPU:
3520                 remove_pset();
3521                 return;
3522         case RT_PCAP:
3523                 remove_pcap();
3524                 return;
3525         case RT_MCAP:
3526                 remove_mcap();
3527                 return;
3528         case RT_ADMIN:
3529                 remove_admin(cmd);
3530                 return;
3531         case RT_SECFLAGS:
3532                 remove_secflags();
3533                 return;
3534         default:
3535                 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
3536                 long_usage(CMD_REMOVE, B_TRUE);
3537                 usage(B_FALSE, HELP_RESOURCES);
3538                 return;
3539         }
3540 }
3541 
3542 static void
3543 remove_property(cmd_t *cmd)
3544 {
3545         char *prop_id;
3546         int err, res_type, prop_type;
3547         property_value_ptr_t pp;
3548         struct zone_rctlvaltab *rctlvaltab;
3549         complex_property_ptr_t cx;
3550 
3551         res_type = resource_scope;
3552         prop_type = cmd->cmd_prop_name[0];
3553         if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3554                 long_usage(CMD_REMOVE, B_TRUE);
3555                 return;
3556         }
3557 
3558         if (cmd->cmd_prop_nv_pairs != 1) {
3559                 long_usage(CMD_ADD, B_TRUE);
3560                 return;
3561         }
3562 
3563         if (initialize(B_TRUE) != Z_OK)
3564                 return;
3565 
3566         switch (res_type) {
3567         case RT_FS:
3568                 if (prop_type != PT_OPTIONS) {
3569                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3570                             B_TRUE);
3571                         long_usage(CMD_REMOVE, B_TRUE);
3572                         usage(B_FALSE, HELP_PROPS);
3573                         return;
3574                 }
3575                 pp = cmd->cmd_property_ptr[0];
3576                 if (pp->pv_type == PROP_VAL_COMPLEX) {
3577                         zerr(gettext("A %s or %s value was expected here."),
3578                             pvt_to_str(PROP_VAL_SIMPLE),
3579                             pvt_to_str(PROP_VAL_LIST));
3580                         saw_error = B_TRUE;
3581                         return;
3582                 }
3583                 if (pp->pv_type == PROP_VAL_SIMPLE) {
3584                         if (pp->pv_simple == NULL) {
3585                                 long_usage(CMD_ADD, B_TRUE);
3586                                 return;
3587                         }
3588                         prop_id = pp->pv_simple;
3589                         err = zonecfg_remove_fs_option(&in_progress_fstab,
3590                             prop_id);
3591                         if (err != Z_OK)
3592                                 zone_perror(pt_to_str(prop_type), err, B_TRUE);
3593                 } else {
3594                         list_property_ptr_t list;
3595 
3596                         for (list = pp->pv_list; list != NULL;
3597                             list = list->lp_next) {
3598                                 prop_id = list->lp_simple;
3599                                 if (prop_id == NULL)
3600                                         break;
3601                                 err = zonecfg_remove_fs_option(
3602                                     &in_progress_fstab, prop_id);
3603                                 if (err != Z_OK)
3604                                         zone_perror(pt_to_str(prop_type), err,
3605                                             B_TRUE);
3606                         }
3607                 }
3608                 return;
3609         case RT_RCTL:
3610                 if (prop_type != PT_VALUE) {
3611                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3612                             B_TRUE);
3613                         long_usage(CMD_REMOVE, B_TRUE);
3614                         usage(B_FALSE, HELP_PROPS);
3615                         return;
3616                 }
3617                 pp = cmd->cmd_property_ptr[0];
3618                 if (pp->pv_type != PROP_VAL_COMPLEX) {
3619                         zerr(gettext("A %s value was expected here."),
3620                             pvt_to_str(PROP_VAL_COMPLEX));
3621                         saw_error = B_TRUE;
3622                         return;
3623                 }
3624                 if ((rctlvaltab = alloc_rctlvaltab()) == NULL) {
3625                         zone_perror(zone, Z_NOMEM, B_TRUE);
3626                         exit(Z_ERR);
3627                 }
3628                 for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
3629                         switch (cx->cp_type) {
3630                         case PT_PRIV:
3631                                 (void) strlcpy(rctlvaltab->zone_rctlval_priv,
3632                                     cx->cp_value,
3633                                     sizeof (rctlvaltab->zone_rctlval_priv));
3634                                 break;
3635                         case PT_LIMIT:
3636                                 (void) strlcpy(rctlvaltab->zone_rctlval_limit,
3637                                     cx->cp_value,
3638                                     sizeof (rctlvaltab->zone_rctlval_limit));
3639                                 break;
3640                         case PT_ACTION:
3641                                 (void) strlcpy(rctlvaltab->zone_rctlval_action,
3642                                     cx->cp_value,
3643                                     sizeof (rctlvaltab->zone_rctlval_action));
3644                                 break;
3645                         default:
3646                                 zone_perror(pt_to_str(prop_type),
3647                                     Z_NO_PROPERTY_TYPE, B_TRUE);
3648                                 long_usage(CMD_ADD, B_TRUE);
3649                                 usage(B_FALSE, HELP_PROPS);
3650                                 zonecfg_free_rctl_value_list(rctlvaltab);
3651                                 return;
3652                         }
3653                 }
3654                 rctlvaltab->zone_rctlval_next = NULL;
3655                 err = zonecfg_remove_rctl_value(&in_progress_rctltab,
3656                     rctlvaltab);
3657                 if (err != Z_OK)
3658                         zone_perror(pt_to_str(prop_type), err, B_TRUE);
3659                 zonecfg_free_rctl_value_list(rctlvaltab);
3660                 return;
3661         case RT_NET:
3662                 if (prop_type != PT_DEFROUTER) {
3663                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
3664                             B_TRUE);
3665                         long_usage(CMD_REMOVE, B_TRUE);
3666                         usage(B_FALSE, HELP_PROPS);
3667                         return;
3668                 } else {
3669                         bzero(&in_progress_nwiftab.zone_nwif_defrouter,
3670                             sizeof (in_progress_nwiftab.zone_nwif_defrouter));
3671                         return;
3672                 }
3673         default:
3674                 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
3675                 long_usage(CMD_REMOVE, B_TRUE);
3676                 usage(B_FALSE, HELP_RESOURCES);
3677                 return;
3678         }
3679 }
3680 
3681 void
3682 remove_func(cmd_t *cmd)
3683 {
3684         if (zone_is_read_only(CMD_REMOVE))
3685                 return;
3686 
3687         assert(cmd != NULL);
3688 
3689         if (global_scope) {
3690                 if (gz_invalid_resource(cmd->cmd_res_type)) {
3691                         zerr(gettext("%s is not a valid resource for the "
3692                             "global zone."), rt_to_str(cmd->cmd_res_type));
3693                         saw_error = B_TRUE;
3694                         return;
3695                 }
3696                 remove_resource(cmd);
3697         } else {
3698                 remove_property(cmd);
3699         }
3700 }
3701 
3702 static void
3703 clear_property(cmd_t *cmd)
3704 {
3705         int res_type, prop_type;
3706 
3707         res_type = resource_scope;
3708         prop_type = cmd->cmd_res_type;
3709         if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
3710                 long_usage(CMD_CLEAR, B_TRUE);
3711                 return;
3712         }
3713 
3714         if (initialize(B_TRUE) != Z_OK)
3715                 return;
3716 
3717         switch (res_type) {
3718         case RT_FS:
3719                 if (prop_type == PT_RAW) {
3720                         in_progress_fstab.zone_fs_raw[0] = '\0';
3721                         need_to_commit = B_TRUE;
3722                         return;
3723                 }
3724                 break;
3725         case RT_DCPU:
3726                 if (prop_type == PT_IMPORTANCE) {
3727                         in_progress_psettab.zone_importance[0] = '\0';
3728                         need_to_commit = B_TRUE;
3729                         return;
3730                 }
3731                 break;
3732         case RT_MCAP:
3733                 switch (prop_type) {
3734                 case PT_PHYSICAL:
3735                         in_progress_mcaptab.zone_physmem_cap[0] = '\0';
3736                         need_to_commit = B_TRUE;
3737                         return;
3738                 case PT_SWAP:
3739                         remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
3740                         return;
3741                 case PT_LOCKED:
3742                         remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
3743                         return;
3744                 }
3745                 break;
3746         case RT_SECFLAGS:
3747                 switch (prop_type) {
3748                 case PT_LOWER:
3749                         in_progress_secflagstab.zone_secflags_lower[0] = '\0';
3750                         need_to_commit = B_TRUE;
3751                         return;
3752                 case PT_DEFAULT:
3753                         in_progress_secflagstab.zone_secflags_default[0] = '\0';
3754                         need_to_commit = B_TRUE;
3755                         return;
3756                 case PT_UPPER:
3757                         in_progress_secflagstab.zone_secflags_upper[0] = '\0';
3758                         need_to_commit = B_TRUE;
3759                         return;
3760                 }
3761                 break;
3762         default:
3763                 break;
3764         }
3765 
3766         zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);
3767 }
3768 
3769 static void
3770 clear_global(cmd_t *cmd)
3771 {
3772         int err, type;
3773 
3774         if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3775                 long_usage(CMD_CLEAR, B_TRUE);
3776                 return;
3777         }
3778 
3779         if (initialize(B_TRUE) != Z_OK)
3780                 return;
3781 
3782         switch (type) {
3783         case PT_ZONENAME:
3784                 /* FALLTHRU */
3785         case PT_ZONEPATH:
3786                 /* FALLTHRU */
3787         case PT_BRAND:
3788                 zone_perror(pt_to_str(type), Z_CLEAR_DISALLOW, B_TRUE);
3789                 return;
3790         case PT_AUTOBOOT:
3791                 /* false is default; we'll treat as equivalent to clearing */
3792                 if ((err = zonecfg_set_autoboot(handle, B_FALSE)) != Z_OK)
3793                         z_cmd_rt_perror(CMD_CLEAR, RT_AUTOBOOT, err, B_TRUE);
3794                 else
3795                         need_to_commit = B_TRUE;
3796                 return;
3797         case PT_POOL:
3798                 if ((err = zonecfg_set_pool(handle, NULL)) != Z_OK)
3799                         z_cmd_rt_perror(CMD_CLEAR, RT_POOL, err, B_TRUE);
3800                 else
3801                         need_to_commit = B_TRUE;
3802                 return;
3803         case PT_LIMITPRIV:
3804                 if ((err = zonecfg_set_limitpriv(handle, NULL)) != Z_OK)
3805                         z_cmd_rt_perror(CMD_CLEAR, RT_LIMITPRIV, err, B_TRUE);
3806                 else
3807                         need_to_commit = B_TRUE;
3808                 return;
3809         case PT_BOOTARGS:
3810                 if ((err = zonecfg_set_bootargs(handle, NULL)) != Z_OK)
3811                         z_cmd_rt_perror(CMD_CLEAR, RT_BOOTARGS, err, B_TRUE);
3812                 else
3813                         need_to_commit = B_TRUE;
3814                 return;
3815         case PT_SCHED:
3816                 if ((err = zonecfg_set_sched(handle, NULL)) != Z_OK)
3817                         z_cmd_rt_perror(CMD_CLEAR, RT_SCHED, err, B_TRUE);
3818                 else
3819                         need_to_commit = B_TRUE;
3820                 return;
3821         case PT_IPTYPE:
3822                 /* shared is default; we'll treat as equivalent to clearing */
3823                 if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK)
3824                         z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, B_TRUE);
3825                 else
3826                         need_to_commit = B_TRUE;
3827                 return;
3828         case PT_MAXLWPS:
3829                 remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS);
3830                 return;
3831         case PT_MAXPROCS:
3832                 remove_aliased_rctl(PT_MAXPROCS, ALIAS_MAXPROCS);
3833                 return;
3834         case PT_MAXSHMMEM:
3835                 remove_aliased_rctl(PT_MAXSHMMEM, ALIAS_MAXSHMMEM);
3836                 return;
3837         case PT_MAXSHMIDS:
3838                 remove_aliased_rctl(PT_MAXSHMIDS, ALIAS_MAXSHMIDS);
3839                 return;
3840         case PT_MAXMSGIDS:
3841                 remove_aliased_rctl(PT_MAXMSGIDS, ALIAS_MAXMSGIDS);
3842                 return;
3843         case PT_MAXSEMIDS:
3844                 remove_aliased_rctl(PT_MAXSEMIDS, ALIAS_MAXSEMIDS);
3845                 return;
3846         case PT_SHARES:
3847                 remove_aliased_rctl(PT_SHARES, ALIAS_SHARES);
3848                 return;
3849         case PT_HOSTID:
3850                 if ((err = zonecfg_set_hostid(handle, NULL)) != Z_OK)
3851                         z_cmd_rt_perror(CMD_CLEAR, RT_HOSTID, err, B_TRUE);
3852                 else
3853                         need_to_commit = B_TRUE;
3854                 return;
3855         case PT_FS_ALLOWED:
3856                 if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK)
3857                         z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE);
3858                 else
3859                         need_to_commit = B_TRUE;
3860                 return;
3861         default:
3862                 zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE);
3863                 long_usage(CMD_CLEAR, B_TRUE);
3864                 usage(B_FALSE, HELP_PROPS);
3865                 return;
3866         }
3867 }
3868 
3869 void
3870 clear_func(cmd_t *cmd)
3871 {
3872         if (zone_is_read_only(CMD_CLEAR))
3873                 return;
3874 
3875         assert(cmd != NULL);
3876 
3877         if (global_scope) {
3878                 if (gz_invalid_property(cmd->cmd_res_type)) {
3879                         zerr(gettext("%s is not a valid property for the "
3880                             "global zone."), pt_to_str(cmd->cmd_res_type));
3881                         saw_error = B_TRUE;
3882                         return;
3883                 }
3884 
3885                 clear_global(cmd);
3886         } else {
3887                 clear_property(cmd);
3888         }
3889 }
3890 
3891 void
3892 select_func(cmd_t *cmd)
3893 {
3894         int type, err, res;
3895         uint64_t limit;
3896         uint64_t tmp;
3897 
3898         if (zone_is_read_only(CMD_SELECT))
3899                 return;
3900 
3901         assert(cmd != NULL);
3902 
3903         if (global_scope) {
3904                 global_scope = B_FALSE;
3905                 resource_scope = cmd->cmd_res_type;
3906                 end_op = CMD_SELECT;
3907         } else {
3908                 scope_usage(CMD_SELECT);
3909                 return;
3910         }
3911 
3912         if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
3913                 long_usage(CMD_SELECT, B_TRUE);
3914                 return;
3915         }
3916 
3917         if (initialize(B_TRUE) != Z_OK)
3918                 return;
3919 
3920         switch (type) {
3921         case RT_FS:
3922                 if ((err = fill_in_fstab(cmd, &old_fstab, B_FALSE)) != Z_OK) {
3923                         z_cmd_rt_perror(CMD_SELECT, RT_FS, err, B_TRUE);
3924                         global_scope = B_TRUE;
3925                 }
3926                 bcopy(&old_fstab, &in_progress_fstab,
3927                     sizeof (struct zone_fstab));
3928                 return;
3929         case RT_NET:
3930                 if ((err = fill_in_nwiftab(cmd, &old_nwiftab, B_FALSE))
3931                     != Z_OK) {
3932                         z_cmd_rt_perror(CMD_SELECT, RT_NET, err, B_TRUE);
3933                         global_scope = B_TRUE;
3934                 }
3935                 bcopy(&old_nwiftab, &in_progress_nwiftab,
3936                     sizeof (struct zone_nwiftab));
3937                 return;
3938         case RT_DEVICE:
3939                 if ((err = fill_in_devtab(cmd, &old_devtab, B_FALSE)) != Z_OK) {
3940                         z_cmd_rt_perror(CMD_SELECT, RT_DEVICE, err, B_TRUE);
3941                         global_scope = B_TRUE;
3942                 }
3943                 bcopy(&old_devtab, &in_progress_devtab,
3944                     sizeof (struct zone_devtab));
3945                 return;
3946         case RT_RCTL:
3947                 if ((err = fill_in_rctltab(cmd, &old_rctltab, B_FALSE))
3948                     != Z_OK) {
3949                         z_cmd_rt_perror(CMD_SELECT, RT_RCTL, err, B_TRUE);
3950                         global_scope = B_TRUE;
3951                 }
3952                 bcopy(&old_rctltab, &in_progress_rctltab,
3953                     sizeof (struct zone_rctltab));
3954                 return;
3955         case RT_ATTR:
3956                 if ((err = fill_in_attrtab(cmd, &old_attrtab, B_FALSE))
3957                     != Z_OK) {
3958                         z_cmd_rt_perror(CMD_SELECT, RT_ATTR, err, B_TRUE);
3959                         global_scope = B_TRUE;
3960                 }
3961                 bcopy(&old_attrtab, &in_progress_attrtab,
3962                     sizeof (struct zone_attrtab));
3963                 return;
3964         case RT_DATASET:
3965                 if ((err = fill_in_dstab(cmd, &old_dstab, B_FALSE)) != Z_OK) {
3966                         z_cmd_rt_perror(CMD_SELECT, RT_DATASET, err, B_TRUE);
3967                         global_scope = B_TRUE;
3968                 }
3969                 bcopy(&old_dstab, &in_progress_dstab,
3970                     sizeof (struct zone_dstab));
3971                 return;
3972         case RT_DCPU:
3973                 if ((err = zonecfg_lookup_pset(handle, &old_psettab)) != Z_OK) {
3974                         z_cmd_rt_perror(CMD_SELECT, RT_DCPU, err, B_TRUE);
3975                         global_scope = B_TRUE;
3976                 }
3977                 bcopy(&old_psettab, &in_progress_psettab,
3978                     sizeof (struct zone_psettab));
3979                 return;
3980         case RT_PCAP:
3981                 if ((err = zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &tmp))
3982                     != Z_OK) {
3983                         z_cmd_rt_perror(CMD_SELECT, RT_PCAP, err, B_TRUE);
3984                         global_scope = B_TRUE;
3985                 }
3986                 return;
3987         case RT_MCAP:
3988                 /* if none of these exist, there is no resource to select */
3989                 if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
3990                     zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
3991                     != Z_OK &&
3992                     zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
3993                     != Z_OK) {
3994                         z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE,
3995                             B_TRUE);
3996                         global_scope = B_TRUE;
3997                 }
3998                 if (res == Z_OK)
3999                         bcopy(&old_mcaptab, &in_progress_mcaptab,
4000                             sizeof (struct zone_mcaptab));
4001                 else
4002                         bzero(&in_progress_mcaptab,
4003                             sizeof (in_progress_mcaptab));
4004                 return;
4005         case RT_ADMIN:
4006                 if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
4007                     != Z_OK) {
4008                         z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err,
4009                             B_TRUE);
4010                         global_scope = B_TRUE;
4011                 }
4012                 bcopy(&old_admintab, &in_progress_admintab,
4013                     sizeof (struct zone_admintab));
4014                 return;
4015         case RT_SECFLAGS:
4016                 if ((err = fill_in_secflagstab(cmd, &old_secflagstab, B_FALSE))
4017                     != Z_OK) {
4018                         z_cmd_rt_perror(CMD_SELECT, RT_SECFLAGS, err,
4019                             B_TRUE);
4020                         global_scope = B_TRUE;
4021                 }
4022                 bcopy(&old_secflagstab, &in_progress_secflagstab,
4023                     sizeof (struct zone_secflagstab));
4024                 return;
4025         default:
4026                 zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
4027                 long_usage(CMD_SELECT, B_TRUE);
4028                 usage(B_FALSE, HELP_RESOURCES);
4029                 return;
4030         }
4031 }
4032 
4033 /*
4034  * Network "addresses" can be one of the following forms:
4035  *      <IPv4 address>
4036  *      <IPv4 address>/<prefix length>
4037  *      <IPv6 address>/<prefix length>
4038  *      <host name>
4039  *      <host name>/<prefix length>
4040  * In other words, the "/" followed by a prefix length is allowed but not
4041  * required for IPv4 addresses and host names, and required for IPv6 addresses.
4042  * If a prefix length is given, it must be in the allowable range: 0 to 32 for
4043  * IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
4044  * Host names must start with an alpha-numeric character, and all subsequent
4045  * characters must be either alpha-numeric or "-".
4046  *
4047  * In some cases, e.g., the nexthop for the defrouter, the context indicates
4048  * that this is the IPV4_ABITS or IPV6_ABITS netmask, in which case we don't
4049  * require the /<prefix length> (and should ignore it if provided).
4050  */
4051 
4052 static int
4053 validate_net_address_syntax(char *address, boolean_t ishost)
4054 {
4055         char *slashp, part1[MAXHOSTNAMELEN];
4056         struct in6_addr in6;
4057         struct in_addr in4;
4058         int prefixlen, i;
4059 
4060         /*
4061          * Copy the part before any '/' into part1 or copy the whole
4062          * thing if there is no '/'.
4063          */
4064         if ((slashp = strchr(address, '/')) != NULL) {
4065                 *slashp = '\0';
4066                 (void) strlcpy(part1, address, sizeof (part1));
4067                 *slashp = '/';
4068                 prefixlen = atoi(++slashp);
4069         } else {
4070                 (void) strlcpy(part1, address, sizeof (part1));
4071         }
4072 
4073         if (ishost && slashp != NULL) {
4074                 zerr(gettext("Warning: prefix length in %s is not required and "
4075                     "will be ignored. The default host-prefix length "
4076                     "will be used"), address);
4077         }
4078 
4079 
4080         if (inet_pton(AF_INET6, part1, &in6) == 1) {
4081                 if (ishost) {
4082                         prefixlen = IPV6_ABITS;
4083                 } else if (slashp == NULL) {
4084                         zerr(gettext("%s: IPv6 addresses "
4085                             "require /prefix-length suffix."), address);
4086                         return (Z_ERR);
4087                 }
4088                 if (prefixlen < 0 || prefixlen > 128) {
4089                         zerr(gettext("%s: IPv6 address "
4090                             "prefix lengths must be 0 - 128."), address);
4091                         return (Z_ERR);
4092                 }
4093                 return (Z_OK);
4094         }
4095 
4096         /* At this point, any /prefix must be for IPv4. */
4097         if (ishost)
4098                 prefixlen = IPV4_ABITS;
4099         else if (slashp != NULL) {
4100                 if (prefixlen < 0 || prefixlen > 32) {
4101                         zerr(gettext("%s: IPv4 address "
4102                             "prefix lengths must be 0 - 32."), address);
4103                         return (Z_ERR);
4104                 }
4105         }
4106 
4107         if (inet_pton(AF_INET, part1, &in4) == 1)
4108                 return (Z_OK);
4109 
4110         /* address may also be a host name */
4111         if (!isalnum(part1[0])) {
4112                 zerr(gettext("%s: bogus host name or network address syntax"),
4113                     part1);
4114                 saw_error = B_TRUE;
4115                 usage(B_FALSE, HELP_NETADDR);
4116                 return (Z_ERR);
4117         }
4118         for (i = 1; part1[i]; i++)
4119                 if (!isalnum(part1[i]) && part1[i] != '-' && part1[i] != '.') {
4120                         zerr(gettext("%s: bogus host name or "
4121                             "network address syntax"), part1);
4122                         saw_error = B_TRUE;
4123                         usage(B_FALSE, HELP_NETADDR);
4124                         return (Z_ERR);
4125                 }
4126         return (Z_OK);
4127 }
4128 
4129 static int
4130 validate_net_physical_syntax(const char *ifname)
4131 {
4132         ifspec_t ifnameprop;
4133         zone_iptype_t iptype;
4134 
4135         if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
4136                 zerr(gettext("zone configuration has an invalid or nonexistent "
4137                     "ip-type property"));
4138                 return (Z_ERR);
4139         }
4140         switch (iptype) {
4141         case ZS_SHARED:
4142                 if (ifparse_ifspec(ifname, &ifnameprop) == B_FALSE) {
4143                         zerr(gettext("%s: invalid physical interface name"),
4144                             ifname);
4145                         return (Z_ERR);
4146                 }
4147                 if (ifnameprop.ifsp_lunvalid) {
4148                         zerr(gettext("%s: LUNs not allowed in physical "
4149                             "interface names"), ifname);
4150                         return (Z_ERR);
4151                 }
4152                 break;
4153         case ZS_EXCLUSIVE:
4154                 if (dladm_valid_linkname(ifname) == B_FALSE) {
4155                         if (strchr(ifname, ':') != NULL)
4156                                 zerr(gettext("%s: physical interface name "
4157                                     "required; logical interface name not "
4158                                     "allowed"), ifname);
4159                         else
4160                                 zerr(gettext("%s: invalid physical interface "
4161                                     "name"), ifname);
4162                         return (Z_ERR);
4163                 }
4164                 break;
4165         }
4166         return (Z_OK);
4167 }
4168 
4169 static boolean_t
4170 valid_fs_type(const char *type)
4171 {
4172         /*
4173          * Is this a valid path component?
4174          */
4175         if (strlen(type) + 1 > MAXNAMELEN)
4176                 return (B_FALSE);
4177         /*
4178          * Make sure a bad value for "type" doesn't make
4179          * /usr/lib/fs/<type>/mount turn into something else.
4180          */
4181         if (strchr(type, '/') != NULL || type[0] == '\0' ||
4182             strcmp(type, ".") == 0 || strcmp(type, "..") == 0)
4183                 return (B_FALSE);
4184         /*
4185          * More detailed verification happens later by zoneadm(1m).
4186          */
4187         return (B_TRUE);
4188 }
4189 
4190 static boolean_t
4191 allow_exclusive()
4192 {
4193         brand_handle_t  bh;
4194         char            brand[MAXNAMELEN];
4195         boolean_t       ret;
4196 
4197         if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
4198                 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
4199                 return (B_FALSE);
4200         }
4201         if ((bh = brand_open(brand)) == NULL) {
4202                 zerr("%s: %s\n", zone, gettext("unknown brand."));
4203                 return (B_FALSE);
4204         }
4205         ret = brand_allow_exclusive_ip(bh);
4206         brand_close(bh);
4207         if (!ret)
4208                 zerr(gettext("%s cannot be '%s' when %s is '%s'."),
4209                     pt_to_str(PT_IPTYPE), "exclusive",
4210                     pt_to_str(PT_BRAND), brand);
4211         return (ret);
4212 }
4213 
4214 static void
4215 set_aliased_rctl(char *alias, int prop_type, char *s)
4216 {
4217         uint64_t limit;
4218         int err;
4219         char tmp[128];
4220 
4221         if (global_zone && strcmp(alias, ALIAS_SHARES) != 0)
4222                 zerr(gettext("WARNING: Setting a global zone resource "
4223                     "control too low could deny\nservice "
4224                     "to even the root user; "
4225                     "this could render the system impossible\n"
4226                     "to administer.  Please use caution."));
4227 
4228         /* convert memory based properties */
4229         if (prop_type == PT_MAXSHMMEM) {
4230                 if (!zonecfg_valid_memlimit(s, &limit)) {
4231                         zerr(gettext("A non-negative number with a required "
4232                             "scale suffix (K, M, G or T) was expected\nhere."));
4233                         saw_error = B_TRUE;
4234                         return;
4235                 }
4236 
4237                 (void) snprintf(tmp, sizeof (tmp), "%llu", limit);
4238                 s = tmp;
4239         }
4240 
4241         if (!zonecfg_aliased_rctl_ok(handle, alias)) {
4242                 zone_perror(pt_to_str(prop_type), Z_ALIAS_DISALLOW, B_FALSE);
4243                 saw_error = B_TRUE;
4244         } else if (!zonecfg_valid_alias_limit(alias, s, &limit)) {
4245                 zerr(gettext("%s property is out of range."),
4246                     pt_to_str(prop_type));
4247                 saw_error = B_TRUE;
4248         } else if ((err = zonecfg_set_aliased_rctl(handle, alias, limit))
4249             != Z_OK) {
4250                 zone_perror(zone, err, B_TRUE);
4251                 saw_error = B_TRUE;
4252         } else {
4253                 need_to_commit = B_TRUE;
4254         }
4255 }
4256 
4257 static void
4258 set_in_progress_nwiftab_address(char *prop_id, int prop_type)
4259 {
4260         if (prop_type == PT_ADDRESS) {
4261                 (void) strlcpy(in_progress_nwiftab.zone_nwif_address, prop_id,
4262                     sizeof (in_progress_nwiftab.zone_nwif_address));
4263         } else {
4264                 assert(prop_type == PT_ALLOWED_ADDRESS);
4265                 (void) strlcpy(in_progress_nwiftab.zone_nwif_allowed_address,
4266                     prop_id,
4267                     sizeof (in_progress_nwiftab.zone_nwif_allowed_address));
4268         }
4269 }
4270 
4271 void
4272 set_func(cmd_t *cmd)
4273 {
4274         char *prop_id;
4275         int arg, err, res_type, prop_type;
4276         property_value_ptr_t pp;
4277         boolean_t autoboot;
4278         zone_iptype_t iptype;
4279         boolean_t force_set = B_FALSE;
4280         size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
4281         uint64_t mem_cap, mem_limit;
4282         float cap;
4283         char *unitp;
4284         struct zone_psettab tmp_psettab;
4285         boolean_t arg_err = B_FALSE;
4286 
4287         if (zone_is_read_only(CMD_SET))
4288                 return;
4289 
4290         assert(cmd != NULL);
4291 
4292         optind = opterr = 0;
4293         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "F")) != EOF) {
4294                 switch (arg) {
4295                 case 'F':
4296                         force_set = B_TRUE;
4297                         break;
4298                 default:
4299                         if (optopt == '?')
4300                                 longer_usage(CMD_SET);
4301                         else
4302                                 short_usage(CMD_SET);
4303                         arg_err = B_TRUE;
4304                         break;
4305                 }
4306         }
4307         if (arg_err)
4308                 return;
4309 
4310         prop_type = cmd->cmd_prop_name[0];
4311         if (global_scope) {
4312                 if (gz_invalid_property(prop_type)) {
4313                         zerr(gettext("%s is not a valid property for the "
4314                             "global zone."), pt_to_str(prop_type));
4315                         saw_error = B_TRUE;
4316                         return;
4317                 }
4318 
4319                 if (prop_type == PT_ZONENAME) {
4320                         res_type = RT_ZONENAME;
4321                 } else if (prop_type == PT_ZONEPATH) {
4322                         res_type = RT_ZONEPATH;
4323                 } else if (prop_type == PT_AUTOBOOT) {
4324                         res_type = RT_AUTOBOOT;
4325                 } else if (prop_type == PT_BRAND) {
4326                         res_type = RT_BRAND;
4327                 } else if (prop_type == PT_POOL) {
4328                         res_type = RT_POOL;
4329                 } else if (prop_type == PT_LIMITPRIV) {
4330                         res_type = RT_LIMITPRIV;
4331                 } else if (prop_type == PT_BOOTARGS) {
4332                         res_type = RT_BOOTARGS;
4333                 } else if (prop_type == PT_SCHED) {
4334                         res_type = RT_SCHED;
4335                 } else if (prop_type == PT_IPTYPE) {
4336                         res_type = RT_IPTYPE;
4337                 } else if (prop_type == PT_MAXLWPS) {
4338                         res_type = RT_MAXLWPS;
4339                 } else if (prop_type == PT_MAXPROCS) {
4340                         res_type = RT_MAXPROCS;
4341                 } else if (prop_type == PT_MAXSHMMEM) {
4342                         res_type = RT_MAXSHMMEM;
4343                 } else if (prop_type == PT_MAXSHMIDS) {
4344                         res_type = RT_MAXSHMIDS;
4345                 } else if (prop_type == PT_MAXMSGIDS) {
4346                         res_type = RT_MAXMSGIDS;
4347                 } else if (prop_type == PT_MAXSEMIDS) {
4348                         res_type = RT_MAXSEMIDS;
4349                 } else if (prop_type == PT_SHARES) {
4350                         res_type = RT_SHARES;
4351                 } else if (prop_type == PT_HOSTID) {
4352                         res_type = RT_HOSTID;
4353                 } else if (prop_type == PT_FS_ALLOWED) {
4354                         res_type = RT_FS_ALLOWED;
4355                 } else {
4356                         zerr(gettext("Cannot set a resource-specific property "
4357                             "from the global scope."));
4358                         saw_error = B_TRUE;
4359                         return;
4360                 }
4361         } else {
4362                 res_type = resource_scope;
4363         }
4364 
4365         if (force_set) {
4366                 if (res_type != RT_ZONEPATH) {
4367                         zerr(gettext("Only zonepath setting can be forced."));
4368                         saw_error = B_TRUE;
4369                         return;
4370                 }
4371                 if (!zonecfg_in_alt_root()) {
4372                         zerr(gettext("Zonepath is changeable only in an "
4373                             "alternate root."));
4374                         saw_error = B_TRUE;
4375                         return;
4376                 }
4377         }
4378 
4379         pp = cmd->cmd_property_ptr[0];
4380         /*
4381          * A nasty expression but not that complicated:
4382          * 1. fs options are simple or list (tested below)
4383          * 2. rctl value's are complex or list (tested below)
4384          * Anything else should be simple.
4385          */
4386         if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
4387             !(res_type == RT_RCTL && prop_type == PT_VALUE) &&
4388             (pp->pv_type != PROP_VAL_SIMPLE ||
4389             (prop_id = pp->pv_simple) == NULL)) {
4390                 zerr(gettext("A %s value was expected here."),
4391                     pvt_to_str(PROP_VAL_SIMPLE));
4392                 saw_error = B_TRUE;
4393                 return;
4394         }
4395         if (prop_type == PT_UNKNOWN) {
4396                 long_usage(CMD_SET, B_TRUE);
4397                 return;
4398         }
4399 
4400         /*
4401          * Special case: the user can change the zone name prior to 'create';
4402          * if the zone already exists, we fall through letting initialize()
4403          * and the rest of the logic run.
4404          */
4405         if (res_type == RT_ZONENAME && got_handle == B_FALSE &&
4406             !state_atleast(ZONE_STATE_CONFIGURED)) {
4407                 if ((err = zonecfg_validate_zonename(prop_id)) != Z_OK) {
4408                         zone_perror(prop_id, err, B_TRUE);
4409                         usage(B_FALSE, HELP_SYNTAX);
4410                         return;
4411                 }
4412                 (void) strlcpy(zone, prop_id, sizeof (zone));
4413                 return;
4414         }
4415 
4416         if (initialize(B_TRUE) != Z_OK)
4417                 return;
4418 
4419         switch (res_type) {
4420         case RT_ZONENAME:
4421                 if ((err = zonecfg_set_name(handle, prop_id)) != Z_OK) {
4422                         /*
4423                          * Use prop_id instead of 'zone' here, since we're
4424                          * reporting a problem about the *new* zonename.
4425                          */
4426                         zone_perror(prop_id, err, B_TRUE);
4427                         usage(B_FALSE, HELP_SYNTAX);
4428                 } else {
4429                         need_to_commit = B_TRUE;
4430                         (void) strlcpy(zone, prop_id, sizeof (zone));
4431                 }
4432                 return;
4433         case RT_ZONEPATH:
4434                 if (!force_set && state_atleast(ZONE_STATE_INSTALLED)) {
4435                         zerr(gettext("Zone %s already installed; %s %s not "
4436                             "allowed."), zone, cmd_to_str(CMD_SET),
4437                             rt_to_str(RT_ZONEPATH));
4438                         return;
4439                 }
4440                 if (validate_zonepath_syntax(prop_id) != Z_OK) {
4441                         saw_error = B_TRUE;
4442                         return;
4443                 }
4444                 if ((err = zonecfg_set_zonepath(handle, prop_id)) != Z_OK)
4445                         zone_perror(zone, err, B_TRUE);
4446                 else
4447                         need_to_commit = B_TRUE;
4448                 return;
4449         case RT_BRAND:
4450                 if (state_atleast(ZONE_STATE_INSTALLED)) {
4451                         zerr(gettext("Zone %s already installed; %s %s not "
4452                             "allowed."), zone, cmd_to_str(CMD_SET),
4453                             rt_to_str(RT_BRAND));
4454                         return;
4455                 }
4456                 if ((err = zonecfg_set_brand(handle, prop_id)) != Z_OK)
4457                         zone_perror(zone, err, B_TRUE);
4458                 else
4459                         need_to_commit = B_TRUE;
4460                 return;
4461         case RT_AUTOBOOT:
4462                 if (strcmp(prop_id, "true") == 0) {
4463                         autoboot = B_TRUE;
4464                 } else if (strcmp(prop_id, "false") == 0) {
4465                         autoboot = B_FALSE;
4466                 } else {
4467                         zerr(gettext("%s value must be '%s' or '%s'."),
4468                             pt_to_str(PT_AUTOBOOT), "true", "false");
4469                         saw_error = B_TRUE;
4470                         return;
4471                 }
4472                 if ((err = zonecfg_set_autoboot(handle, autoboot)) != Z_OK)
4473                         zone_perror(zone, err, B_TRUE);
4474                 else
4475                         need_to_commit = B_TRUE;
4476                 return;
4477         case RT_POOL:
4478                 /* don't allow use of the reserved temporary pool names */
4479                 if (strncmp("SUNW", prop_id, 4) == 0) {
4480                         zerr(gettext("pool names starting with SUNW are "
4481                             "reserved."));
4482                         saw_error = B_TRUE;
4483                         return;
4484                 }
4485 
4486                 /* can't set pool if dedicated-cpu exists */
4487                 if (zonecfg_lookup_pset(handle, &tmp_psettab) == Z_OK) {
4488                         zerr(gettext("The %s resource already exists.  "
4489                             "A persistent pool is incompatible\nwith the %s "
4490                             "resource."), rt_to_str(RT_DCPU),
4491                             rt_to_str(RT_DCPU));
4492                         saw_error = B_TRUE;
4493                         return;
4494                 }
4495 
4496                 if ((err = zonecfg_set_pool(handle, prop_id)) != Z_OK)
4497                         zone_perror(zone, err, B_TRUE);
4498                 else
4499                         need_to_commit = B_TRUE;
4500                 return;
4501         case RT_LIMITPRIV:
4502                 if ((err = zonecfg_set_limitpriv(handle, prop_id)) != Z_OK)
4503                         zone_perror(zone, err, B_TRUE);
4504                 else
4505                         need_to_commit = B_TRUE;
4506                 return;
4507         case RT_BOOTARGS:
4508                 if ((err = zonecfg_set_bootargs(handle, prop_id)) != Z_OK)
4509                         zone_perror(zone, err, B_TRUE);
4510                 else
4511                         need_to_commit = B_TRUE;
4512                 return;
4513         case RT_SCHED:
4514                 if ((err = zonecfg_set_sched(handle, prop_id)) != Z_OK)
4515                         zone_perror(zone, err, B_TRUE);
4516                 else
4517                         need_to_commit = B_TRUE;
4518                 return;
4519         case RT_IPTYPE:
4520                 if (strcmp(prop_id, "shared") == 0) {
4521                         iptype = ZS_SHARED;
4522                 } else if (strcmp(prop_id, "exclusive") == 0) {
4523                         iptype = ZS_EXCLUSIVE;
4524                 } else {
4525                         zerr(gettext("%s value must be '%s' or '%s'."),
4526                             pt_to_str(PT_IPTYPE), "shared", "exclusive");
4527                         saw_error = B_TRUE;
4528                         return;
4529                 }
4530                 if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) {
4531                         saw_error = B_TRUE;
4532                         return;
4533                 }
4534                 if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK)
4535                         zone_perror(zone, err, B_TRUE);
4536                 else
4537                         need_to_commit = B_TRUE;
4538                 return;
4539         case RT_MAXLWPS:
4540                 set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id);
4541                 return;
4542         case RT_MAXPROCS:
4543                 set_aliased_rctl(ALIAS_MAXPROCS, prop_type, prop_id);
4544                 return;
4545         case RT_MAXSHMMEM:
4546                 set_aliased_rctl(ALIAS_MAXSHMMEM, prop_type, prop_id);
4547                 return;
4548         case RT_MAXSHMIDS:
4549                 set_aliased_rctl(ALIAS_MAXSHMIDS, prop_type, prop_id);
4550                 return;
4551         case RT_MAXMSGIDS:
4552                 set_aliased_rctl(ALIAS_MAXMSGIDS, prop_type, prop_id);
4553                 return;
4554         case RT_MAXSEMIDS:
4555                 set_aliased_rctl(ALIAS_MAXSEMIDS, prop_type, prop_id);
4556                 return;
4557         case RT_SHARES:
4558                 set_aliased_rctl(ALIAS_SHARES, prop_type, prop_id);
4559                 return;
4560         case RT_HOSTID:
4561                 if ((err = zonecfg_set_hostid(handle, prop_id)) != Z_OK) {
4562                         if (err == Z_TOO_BIG) {
4563                                 zerr(gettext("hostid string is too large: %s"),
4564                                     prop_id);
4565                                 saw_error = B_TRUE;
4566                         } else {
4567                                 zone_perror(pt_to_str(prop_type), err, B_TRUE);
4568                         }
4569                         return;
4570                 }
4571                 need_to_commit = B_TRUE;
4572                 return;
4573         case RT_FS_ALLOWED:
4574                 if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
4575                         zone_perror(zone, err, B_TRUE);
4576                 else
4577                         need_to_commit = B_TRUE;
4578                 return;
4579         case RT_FS:
4580                 switch (prop_type) {
4581                 case PT_DIR:
4582                         (void) strlcpy(in_progress_fstab.zone_fs_dir, prop_id,
4583                             sizeof (in_progress_fstab.zone_fs_dir));
4584                         return;
4585                 case PT_SPECIAL:
4586                         (void) strlcpy(in_progress_fstab.zone_fs_special,
4587                             prop_id,
4588                             sizeof (in_progress_fstab.zone_fs_special));
4589                         return;
4590                 case PT_RAW:
4591                         (void) strlcpy(in_progress_fstab.zone_fs_raw,
4592                             prop_id, sizeof (in_progress_fstab.zone_fs_raw));
4593                         return;
4594                 case PT_TYPE:
4595                         if (!valid_fs_type(prop_id)) {
4596                                 zerr(gettext("\"%s\" is not a valid %s."),
4597                                     prop_id, pt_to_str(PT_TYPE));
4598                                 saw_error = B_TRUE;
4599                                 return;
4600                         }
4601                         (void) strlcpy(in_progress_fstab.zone_fs_type, prop_id,
4602                             sizeof (in_progress_fstab.zone_fs_type));
4603                         return;
4604                 case PT_OPTIONS:
4605                         if (pp->pv_type != PROP_VAL_SIMPLE &&
4606                             pp->pv_type != PROP_VAL_LIST) {
4607                                 zerr(gettext("A %s or %s value was expected "
4608                                     "here."), pvt_to_str(PROP_VAL_SIMPLE),
4609                                     pvt_to_str(PROP_VAL_LIST));
4610                                 saw_error = B_TRUE;
4611                                 return;
4612                         }
4613                         zonecfg_free_fs_option_list(
4614                             in_progress_fstab.zone_fs_options);
4615                         in_progress_fstab.zone_fs_options = NULL;
4616                         if (!(pp->pv_type == PROP_VAL_LIST &&
4617                             pp->pv_list == NULL))
4618                                 add_property(cmd);
4619                         return;
4620                 default:
4621                         break;
4622                 }
4623                 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4624                 long_usage(CMD_SET, B_TRUE);
4625                 usage(B_FALSE, HELP_PROPS);
4626                 return;
4627         case RT_NET:
4628                 switch (prop_type) {
4629                 case PT_ADDRESS:
4630                 case PT_ALLOWED_ADDRESS:
4631                         if (validate_net_address_syntax(prop_id, B_FALSE)
4632                             != Z_OK) {
4633                                 saw_error = B_TRUE;
4634                                 return;
4635                         }
4636                         set_in_progress_nwiftab_address(prop_id, prop_type);
4637                         break;
4638                 case PT_PHYSICAL:
4639                         if (validate_net_physical_syntax(prop_id) != Z_OK) {
4640                                 saw_error = B_TRUE;
4641                                 return;
4642                         }
4643                         (void) strlcpy(in_progress_nwiftab.zone_nwif_physical,
4644                             prop_id,
4645                             sizeof (in_progress_nwiftab.zone_nwif_physical));
4646                         break;
4647                 case PT_DEFROUTER:
4648                         if (validate_net_address_syntax(prop_id, B_TRUE)
4649                             != Z_OK) {
4650                                 saw_error = B_TRUE;
4651                                 return;
4652                         }
4653                         (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter,
4654                             prop_id,
4655                             sizeof (in_progress_nwiftab.zone_nwif_defrouter));
4656                         break;
4657                 default:
4658                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4659                             B_TRUE);
4660                         long_usage(CMD_SET, B_TRUE);
4661                         usage(B_FALSE, HELP_PROPS);
4662                         return;
4663                 }
4664                 return;
4665         case RT_DEVICE:
4666                 switch (prop_type) {
4667                 case PT_MATCH:
4668                         (void) strlcpy(in_progress_devtab.zone_dev_match,
4669                             prop_id,
4670                             sizeof (in_progress_devtab.zone_dev_match));
4671                         break;
4672                 default:
4673                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4674                             B_TRUE);
4675                         long_usage(CMD_SET, B_TRUE);
4676                         usage(B_FALSE, HELP_PROPS);
4677                         return;
4678                 }
4679                 return;
4680         case RT_RCTL:
4681                 switch (prop_type) {
4682                 case PT_NAME:
4683                         if (!zonecfg_valid_rctlname(prop_id)) {
4684                                 zerr(gettext("'%s' is not a valid zone %s "
4685                                     "name."), prop_id, rt_to_str(RT_RCTL));
4686                                 return;
4687                         }
4688                         (void) strlcpy(in_progress_rctltab.zone_rctl_name,
4689                             prop_id,
4690                             sizeof (in_progress_rctltab.zone_rctl_name));
4691                         break;
4692                 case PT_VALUE:
4693                         if (pp->pv_type != PROP_VAL_COMPLEX &&
4694                             pp->pv_type != PROP_VAL_LIST) {
4695                                 zerr(gettext("A %s or %s value was expected "
4696                                     "here."), pvt_to_str(PROP_VAL_COMPLEX),
4697                                     pvt_to_str(PROP_VAL_LIST));
4698                                 saw_error = B_TRUE;
4699                                 return;
4700                         }
4701                         zonecfg_free_rctl_value_list(
4702                             in_progress_rctltab.zone_rctl_valptr);
4703                         in_progress_rctltab.zone_rctl_valptr = NULL;
4704                         if (!(pp->pv_type == PROP_VAL_LIST &&
4705                             pp->pv_list == NULL))
4706                                 add_property(cmd);
4707                         break;
4708                 default:
4709                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4710                             B_TRUE);
4711                         long_usage(CMD_SET, B_TRUE);
4712                         usage(B_FALSE, HELP_PROPS);
4713                         return;
4714                 }
4715                 return;
4716         case RT_ATTR:
4717                 switch (prop_type) {
4718                 case PT_NAME:
4719                         (void) strlcpy(in_progress_attrtab.zone_attr_name,
4720                             prop_id,
4721                             sizeof (in_progress_attrtab.zone_attr_name));
4722                         break;
4723                 case PT_TYPE:
4724                         (void) strlcpy(in_progress_attrtab.zone_attr_type,
4725                             prop_id,
4726                             sizeof (in_progress_attrtab.zone_attr_type));
4727                         break;
4728                 case PT_VALUE:
4729                         (void) strlcpy(in_progress_attrtab.zone_attr_value,
4730                             prop_id,
4731                             sizeof (in_progress_attrtab.zone_attr_value));
4732                         break;
4733                 default:
4734                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4735                             B_TRUE);
4736                         long_usage(CMD_SET, B_TRUE);
4737                         usage(B_FALSE, HELP_PROPS);
4738                         return;
4739                 }
4740                 return;
4741         case RT_DATASET:
4742                 switch (prop_type) {
4743                 case PT_NAME:
4744                         (void) strlcpy(in_progress_dstab.zone_dataset_name,
4745                             prop_id,
4746                             sizeof (in_progress_dstab.zone_dataset_name));
4747                         return;
4748                 default:
4749                         break;
4750                 }
4751                 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4752                 long_usage(CMD_SET, B_TRUE);
4753                 usage(B_FALSE, HELP_PROPS);
4754                 return;
4755         case RT_DCPU:
4756                 switch (prop_type) {
4757                 char *lowp, *highp;
4758 
4759                 case PT_NCPUS:
4760                         lowp = prop_id;
4761                         if ((highp = strchr(prop_id, '-')) != NULL)
4762                                 *highp++ = '\0';
4763                         else
4764                                 highp = lowp;
4765 
4766                         /* Make sure the input makes sense. */
4767                         if (!zonecfg_valid_ncpus(lowp, highp)) {
4768                                 zerr(gettext("%s property is out of range."),
4769                                     pt_to_str(PT_NCPUS));
4770                                 saw_error = B_TRUE;
4771                                 return;
4772                         }
4773 
4774                         (void) strlcpy(
4775                             in_progress_psettab.zone_ncpu_min, lowp,
4776                             sizeof (in_progress_psettab.zone_ncpu_min));
4777                         (void) strlcpy(
4778                             in_progress_psettab.zone_ncpu_max, highp,
4779                             sizeof (in_progress_psettab.zone_ncpu_max));
4780                         return;
4781                 case PT_IMPORTANCE:
4782                         /* Make sure the value makes sense. */
4783                         if (!zonecfg_valid_importance(prop_id)) {
4784                                 zerr(gettext("%s property is out of range."),
4785                                     pt_to_str(PT_IMPORTANCE));
4786                                 saw_error = B_TRUE;
4787                                 return;
4788                         }
4789 
4790                         (void) strlcpy(in_progress_psettab.zone_importance,
4791                             prop_id,
4792                             sizeof (in_progress_psettab.zone_importance));
4793                         return;
4794                 default:
4795                         break;
4796                 }
4797                 zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE, B_TRUE);
4798                 long_usage(CMD_SET, B_TRUE);
4799                 usage(B_FALSE, HELP_PROPS);
4800                 return;
4801         case RT_PCAP:
4802                 if (prop_type != PT_NCPUS) {
4803                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4804                             B_TRUE);
4805                         long_usage(CMD_SET, B_TRUE);
4806                         usage(B_FALSE, HELP_PROPS);
4807                         return;
4808                 }
4809 
4810                 /*
4811                  * We already checked that an rctl alias is allowed in
4812                  * the add_resource() function.
4813                  */
4814 
4815                 if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
4816                     (int)(cap * 100) < 1) {
4817                         zerr(gettext("%s property is out of range."),
4818                             pt_to_str(PT_NCPUS));
4819                         saw_error = B_TRUE;
4820                         return;
4821                 }
4822 
4823                 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
4824                     (int)(cap * 100))) != Z_OK)
4825                         zone_perror(zone, err, B_TRUE);
4826                 else
4827                         need_to_commit = B_TRUE;
4828                 return;
4829         case RT_MCAP:
4830                 switch (prop_type) {
4831                 case PT_PHYSICAL:
4832                         if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4833                                 zerr(gettext("A positive number with a "
4834                                     "required scale suffix (K, M, G or T) was "
4835                                     "expected here."));
4836                                 saw_error = B_TRUE;
4837                         } else if (mem_cap < ONE_MB) {
4838                                 zerr(gettext("%s value is too small.  It must "
4839                                     "be at least 1M."), pt_to_str(PT_PHYSICAL));
4840                                 saw_error = B_TRUE;
4841                         } else {
4842                                 snprintf(in_progress_mcaptab.zone_physmem_cap,
4843                                     physmem_size, "%llu", mem_cap);
4844                         }
4845                         break;
4846                 case PT_SWAP:
4847                         /*
4848                          * We have to check if an rctl is allowed here since
4849                          * there might already be a rctl defined that blocks
4850                          * the alias.
4851                          */
4852                         if (!zonecfg_aliased_rctl_ok(handle, ALIAS_MAXSWAP)) {
4853                                 zone_perror(pt_to_str(PT_MAXSWAP),
4854                                     Z_ALIAS_DISALLOW, B_FALSE);
4855                                 saw_error = B_TRUE;
4856                                 return;
4857                         }
4858 
4859                         if (global_zone)
4860                                 mem_limit = ONE_MB * 100;
4861                         else
4862                                 mem_limit = ONE_MB * 50;
4863 
4864                         if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4865                                 zerr(gettext("A positive number with a "
4866                                     "required scale suffix (K, M, G or T) was "
4867                                     "expected here."));
4868                                 saw_error = B_TRUE;
4869                         } else if (mem_cap < mem_limit) {
4870                                 char buf[128];
4871 
4872                                 (void) snprintf(buf, sizeof (buf), "%llu",
4873                                     mem_limit);
4874                                 bytes_to_units(buf, buf, sizeof (buf));
4875                                 zerr(gettext("%s value is too small.  It must "
4876                                     "be at least %s."), pt_to_str(PT_SWAP),
4877                                     buf);
4878                                 saw_error = B_TRUE;
4879                         } else {
4880                                 if ((err = zonecfg_set_aliased_rctl(handle,
4881                                     ALIAS_MAXSWAP, mem_cap)) != Z_OK)
4882                                         zone_perror(zone, err, B_TRUE);
4883                                 else
4884                                         need_to_commit = B_TRUE;
4885                         }
4886                         break;
4887                 case PT_LOCKED:
4888                         /*
4889                          * We have to check if an rctl is allowed here since
4890                          * there might already be a rctl defined that blocks
4891                          * the alias.
4892                          */
4893                         if (!zonecfg_aliased_rctl_ok(handle,
4894                             ALIAS_MAXLOCKEDMEM)) {
4895                                 zone_perror(pt_to_str(PT_LOCKED),
4896                                     Z_ALIAS_DISALLOW, B_FALSE);
4897                                 saw_error = B_TRUE;
4898                                 return;
4899                         }
4900 
4901                         if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
4902                                 zerr(gettext("A non-negative number with a "
4903                                     "required scale suffix (K, M, G or T) was "
4904                                     "expected\nhere."));
4905                                 saw_error = B_TRUE;
4906                         } else {
4907                                 if ((err = zonecfg_set_aliased_rctl(handle,
4908                                     ALIAS_MAXLOCKEDMEM, mem_cap)) != Z_OK)
4909                                         zone_perror(zone, err, B_TRUE);
4910                                 else
4911                                         need_to_commit = B_TRUE;
4912                         }
4913                         break;
4914                 default:
4915                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4916                             B_TRUE);
4917                         long_usage(CMD_SET, B_TRUE);
4918                         usage(B_FALSE, HELP_PROPS);
4919                         return;
4920                 }
4921                 return;
4922         case RT_ADMIN:
4923                 switch (prop_type) {
4924                 case PT_USER:
4925                         (void) strlcpy(in_progress_admintab.zone_admin_user,
4926                             prop_id,
4927                             sizeof (in_progress_admintab.zone_admin_user));
4928                         return;
4929                 case PT_AUTHS:
4930                         (void) strlcpy(in_progress_admintab.zone_admin_auths,
4931                             prop_id,
4932                             sizeof (in_progress_admintab.zone_admin_auths));
4933                         return;
4934                 default:
4935                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4936                             B_TRUE);
4937                         long_usage(CMD_SET, B_TRUE);
4938                         usage(B_FALSE, HELP_PROPS);
4939                         return;
4940                 }
4941         case RT_SECFLAGS: {
4942                 char *propstr;
4943 
4944                 switch (prop_type) {
4945                 case PT_DEFAULT:
4946                         propstr = in_progress_secflagstab.zone_secflags_default;
4947                         break;
4948                 case PT_UPPER:
4949                         propstr = in_progress_secflagstab.zone_secflags_upper;
4950                         break;
4951                 case PT_LOWER:
4952                         propstr = in_progress_secflagstab.zone_secflags_lower;
4953                         break;
4954                 default:
4955                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
4956                             B_TRUE);
4957                         long_usage(CMD_SET, B_TRUE);
4958                         usage(B_FALSE, HELP_PROPS);
4959                         return;
4960                 }
4961                 (void) strlcpy(propstr, prop_id, ZONECFG_SECFLAGS_MAX);
4962                 return;
4963         }
4964         default:
4965                 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
4966                 long_usage(CMD_SET, B_TRUE);
4967                 usage(B_FALSE, HELP_RESOURCES);
4968                 return;
4969         }
4970 }
4971 
4972 static void
4973 output_prop(FILE *fp, int pnum, char *pval, boolean_t print_notspec)
4974 {
4975         char *qstr;
4976 
4977         if (*pval != '\0') {
4978                 qstr = quoteit(pval);
4979                 if (pnum == PT_SWAP || pnum == PT_LOCKED)
4980                         (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(pnum),
4981                             qstr);
4982                 else
4983                         (void) fprintf(fp, "\t%s: %s\n", pt_to_str(pnum), qstr);
4984                 free(qstr);
4985         } else if (print_notspec)
4986                 (void) fprintf(fp, gettext("\t%s not specified\n"),
4987                     pt_to_str(pnum));
4988 }
4989 
4990 static void
4991 info_zonename(zone_dochandle_t handle, FILE *fp)
4992 {
4993         char zonename[ZONENAME_MAX];
4994 
4995         if (zonecfg_get_name(handle, zonename, sizeof (zonename)) == Z_OK)
4996                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONENAME),
4997                     zonename);
4998         else
4999                 (void) fprintf(fp, gettext("%s not specified\n"),
5000                     pt_to_str(PT_ZONENAME));
5001 }
5002 
5003 static void
5004 info_zonepath(zone_dochandle_t handle, FILE *fp)
5005 {
5006         char zonepath[MAXPATHLEN];
5007 
5008         if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) == Z_OK)
5009                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_ZONEPATH),
5010                     zonepath);
5011         else {
5012                 (void) fprintf(fp, gettext("%s not specified\n"),
5013                     pt_to_str(PT_ZONEPATH));
5014         }
5015 }
5016 
5017 static void
5018 info_brand(zone_dochandle_t handle, FILE *fp)
5019 {
5020         char brand[MAXNAMELEN];
5021 
5022         if (zonecfg_get_brand(handle, brand, sizeof (brand)) == Z_OK)
5023                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BRAND),
5024                     brand);
5025         else
5026                 (void) fprintf(fp, "%s %s\n", pt_to_str(PT_BRAND),
5027                     gettext("not specified"));
5028 }
5029 
5030 static void
5031 info_autoboot(zone_dochandle_t handle, FILE *fp)
5032 {
5033         boolean_t autoboot;
5034         int err;
5035 
5036         if ((err = zonecfg_get_autoboot(handle, &autoboot)) == Z_OK)
5037                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_AUTOBOOT),
5038                     autoboot ? "true" : "false");
5039         else
5040                 zone_perror(zone, err, B_TRUE);
5041 }
5042 
5043 static void
5044 info_pool(zone_dochandle_t handle, FILE *fp)
5045 {
5046         char pool[MAXNAMELEN];
5047         int err;
5048 
5049         if ((err = zonecfg_get_pool(handle, pool, sizeof (pool))) == Z_OK)
5050                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_POOL), pool);
5051         else
5052                 zone_perror(zone, err, B_TRUE);
5053 }
5054 
5055 static void
5056 info_limitpriv(zone_dochandle_t handle, FILE *fp)
5057 {
5058         char *limitpriv;
5059         int err;
5060 
5061         if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) == Z_OK) {
5062                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_LIMITPRIV),
5063                     limitpriv);
5064                 free(limitpriv);
5065         } else {
5066                 zone_perror(zone, err, B_TRUE);
5067         }
5068 }
5069 
5070 static void
5071 info_bootargs(zone_dochandle_t handle, FILE *fp)
5072 {
5073         char bootargs[BOOTARGS_MAX];
5074         int err;
5075 
5076         if ((err = zonecfg_get_bootargs(handle, bootargs,
5077             sizeof (bootargs))) == Z_OK) {
5078                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_BOOTARGS),
5079                     bootargs);
5080         } else {
5081                 zone_perror(zone, err, B_TRUE);
5082         }
5083 }
5084 
5085 static void
5086 info_sched(zone_dochandle_t handle, FILE *fp)
5087 {
5088         char sched[MAXNAMELEN];
5089         int err;
5090 
5091         if ((err = zonecfg_get_sched_class(handle, sched, sizeof (sched)))
5092             == Z_OK) {
5093                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_SCHED), sched);
5094         } else {
5095                 zone_perror(zone, err, B_TRUE);
5096         }
5097 }
5098 
5099 static void
5100 info_iptype(zone_dochandle_t handle, FILE *fp)
5101 {
5102         zone_iptype_t iptype;
5103         int err;
5104 
5105         if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) {
5106                 switch (iptype) {
5107                 case ZS_SHARED:
5108                         (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5109                             "shared");
5110                         break;
5111                 case ZS_EXCLUSIVE:
5112                         (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
5113                             "exclusive");
5114                         break;
5115                 }
5116         } else {
5117                 zone_perror(zone, err, B_TRUE);
5118         }
5119 }
5120 
5121 static void
5122 info_hostid(zone_dochandle_t handle, FILE *fp)
5123 {
5124         char hostidp[HW_HOSTID_LEN];
5125         int err;
5126 
5127         if ((err = zonecfg_get_hostid(handle, hostidp,
5128             sizeof (hostidp))) == Z_OK) {
5129                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp);
5130         } else if (err == Z_BAD_PROPERTY) {
5131                 (void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID));
5132         } else {
5133                 zone_perror(zone, err, B_TRUE);
5134         }
5135 }
5136 
5137 static void
5138 info_fs_allowed(zone_dochandle_t handle, FILE *fp)
5139 {
5140         char fsallowedp[ZONE_FS_ALLOWED_MAX];
5141         int err;
5142 
5143         if ((err = zonecfg_get_fs_allowed(handle, fsallowedp,
5144             sizeof (fsallowedp))) == Z_OK) {
5145                 (void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED),
5146                     fsallowedp);
5147         } else if (err == Z_BAD_PROPERTY) {
5148                 (void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED));
5149         } else {
5150                 zone_perror(zone, err, B_TRUE);
5151         }
5152 }
5153 
5154 static void
5155 output_fs(FILE *fp, struct zone_fstab *fstab)
5156 {
5157         zone_fsopt_t *this;
5158 
5159         (void) fprintf(fp, "%s:\n", rt_to_str(RT_FS));
5160         output_prop(fp, PT_DIR, fstab->zone_fs_dir, B_TRUE);
5161         output_prop(fp, PT_SPECIAL, fstab->zone_fs_special, B_TRUE);
5162         output_prop(fp, PT_RAW, fstab->zone_fs_raw, B_TRUE);
5163         output_prop(fp, PT_TYPE, fstab->zone_fs_type, B_TRUE);
5164         (void) fprintf(fp, "\t%s: [", pt_to_str(PT_OPTIONS));
5165         for (this = fstab->zone_fs_options; this != NULL;
5166             this = this->zone_fsopt_next) {
5167                 if (strchr(this->zone_fsopt_opt, '='))
5168                         (void) fprintf(fp, "\"%s\"", this->zone_fsopt_opt);
5169                 else
5170                         (void) fprintf(fp, "%s", this->zone_fsopt_opt);
5171                 if (this->zone_fsopt_next != NULL)
5172                         (void) fprintf(fp, ",");
5173         }
5174         (void) fprintf(fp, "]\n");
5175 }
5176 
5177 static void
5178 info_fs(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5179 {
5180         struct zone_fstab lookup, user;
5181         boolean_t output = B_FALSE;
5182 
5183         if (zonecfg_setfsent(handle) != Z_OK)
5184                 return;
5185         while (zonecfg_getfsent(handle, &lookup) == Z_OK) {
5186                 if (cmd->cmd_prop_nv_pairs == 0) {
5187                         output_fs(fp, &lookup);
5188                         goto loopend;
5189                 }
5190                 if (fill_in_fstab(cmd, &user, B_TRUE) != Z_OK)
5191                         goto loopend;
5192                 if (strlen(user.zone_fs_dir) > 0 &&
5193                     strcmp(user.zone_fs_dir, lookup.zone_fs_dir) != 0)
5194                         goto loopend;   /* no match */
5195                 if (strlen(user.zone_fs_special) > 0 &&
5196                     strcmp(user.zone_fs_special, lookup.zone_fs_special) != 0)
5197                         goto loopend;   /* no match */
5198                 if (strlen(user.zone_fs_type) > 0 &&
5199                     strcmp(user.zone_fs_type, lookup.zone_fs_type) != 0)
5200                         goto loopend;   /* no match */
5201                 output_fs(fp, &lookup);
5202                 output = B_TRUE;
5203 loopend:
5204                 zonecfg_free_fs_option_list(lookup.zone_fs_options);
5205         }
5206         (void) zonecfg_endfsent(handle);
5207         /*
5208          * If a property n/v pair was specified, warn the user if there was
5209          * nothing to output.
5210          */
5211         if (!output && cmd->cmd_prop_nv_pairs > 0)
5212                 (void) printf(gettext("No such %s resource.\n"),
5213                     rt_to_str(RT_FS));
5214 }
5215 
5216 static void
5217 output_net(FILE *fp, struct zone_nwiftab *nwiftab)
5218 {
5219         (void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
5220         output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
5221         output_prop(fp, PT_ALLOWED_ADDRESS,
5222             nwiftab->zone_nwif_allowed_address, B_TRUE);
5223         output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
5224         output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
5225 }
5226 
5227 static void
5228 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5229 {
5230         struct zone_nwiftab lookup, user;
5231         boolean_t output = B_FALSE;
5232 
5233         if (zonecfg_setnwifent(handle) != Z_OK)
5234                 return;
5235         while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
5236                 if (cmd->cmd_prop_nv_pairs == 0) {
5237                         output_net(fp, &lookup);
5238                         continue;
5239                 }
5240                 if (fill_in_nwiftab(cmd, &user, B_TRUE) != Z_OK)
5241                         continue;
5242                 if (strlen(user.zone_nwif_physical) > 0 &&
5243                     strcmp(user.zone_nwif_physical,
5244                     lookup.zone_nwif_physical) != 0)
5245                         continue;       /* no match */
5246                 /* If present make sure it matches */
5247                 if (strlen(user.zone_nwif_address) > 0 &&
5248                     !zonecfg_same_net_address(user.zone_nwif_address,
5249                     lookup.zone_nwif_address))
5250                         continue;       /* no match */
5251                 output_net(fp, &lookup);
5252                 output = B_TRUE;
5253         }
5254         (void) zonecfg_endnwifent(handle);
5255         /*
5256          * If a property n/v pair was specified, warn the user if there was
5257          * nothing to output.
5258          */
5259         if (!output && cmd->cmd_prop_nv_pairs > 0)
5260                 (void) printf(gettext("No such %s resource.\n"),
5261                     rt_to_str(RT_NET));
5262 }
5263 
5264 static void
5265 output_dev(FILE *fp, struct zone_devtab *devtab)
5266 {
5267         (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
5268         output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
5269 }
5270 
5271 static void
5272 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5273 {
5274         struct zone_devtab lookup, user;
5275         boolean_t output = B_FALSE;
5276 
5277         if (zonecfg_setdevent(handle) != Z_OK)
5278                 return;
5279         while (zonecfg_getdevent(handle, &lookup) == Z_OK) {
5280                 if (cmd->cmd_prop_nv_pairs == 0) {
5281                         output_dev(fp, &lookup);
5282                         continue;
5283                 }
5284                 if (fill_in_devtab(cmd, &user, B_TRUE) != Z_OK)
5285                         continue;
5286                 if (strlen(user.zone_dev_match) > 0 &&
5287                     strcmp(user.zone_dev_match, lookup.zone_dev_match) != 0)
5288                         continue;       /* no match */
5289                 output_dev(fp, &lookup);
5290                 output = B_TRUE;
5291         }
5292         (void) zonecfg_enddevent(handle);
5293         /*
5294          * If a property n/v pair was specified, warn the user if there was
5295          * nothing to output.
5296          */
5297         if (!output && cmd->cmd_prop_nv_pairs > 0)
5298                 (void) printf(gettext("No such %s resource.\n"),
5299                     rt_to_str(RT_DEVICE));
5300 }
5301 
5302 static void
5303 output_rctl(FILE *fp, struct zone_rctltab *rctltab)
5304 {
5305         struct zone_rctlvaltab *valptr;
5306 
5307         (void) fprintf(fp, "%s:\n", rt_to_str(RT_RCTL));
5308         output_prop(fp, PT_NAME, rctltab->zone_rctl_name, B_TRUE);
5309         for (valptr = rctltab->zone_rctl_valptr; valptr != NULL;
5310             valptr = valptr->zone_rctlval_next) {
5311                 fprintf(fp, "\t%s: (%s=%s,%s=%s,%s=%s)\n",
5312                     pt_to_str(PT_VALUE),
5313                     pt_to_str(PT_PRIV), valptr->zone_rctlval_priv,
5314                     pt_to_str(PT_LIMIT), valptr->zone_rctlval_limit,
5315                     pt_to_str(PT_ACTION), valptr->zone_rctlval_action);
5316         }
5317 }
5318 
5319 static void
5320 info_rctl(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5321 {
5322         struct zone_rctltab lookup, user;
5323         boolean_t output = B_FALSE;
5324 
5325         if (zonecfg_setrctlent(handle) != Z_OK)
5326                 return;
5327         while (zonecfg_getrctlent(handle, &lookup) == Z_OK) {
5328                 if (cmd->cmd_prop_nv_pairs == 0) {
5329                         output_rctl(fp, &lookup);
5330                 } else if (fill_in_rctltab(cmd, &user, B_TRUE) == Z_OK &&
5331                     (strlen(user.zone_rctl_name) == 0 ||
5332                     strcmp(user.zone_rctl_name, lookup.zone_rctl_name) == 0)) {
5333                         output_rctl(fp, &lookup);
5334                         output = B_TRUE;
5335                 }
5336                 zonecfg_free_rctl_value_list(lookup.zone_rctl_valptr);
5337         }
5338         (void) zonecfg_endrctlent(handle);
5339         /*
5340          * If a property n/v pair was specified, warn the user if there was
5341          * nothing to output.
5342          */
5343         if (!output && cmd->cmd_prop_nv_pairs > 0)
5344                 (void) printf(gettext("No such %s resource.\n"),
5345                     rt_to_str(RT_RCTL));
5346 }
5347 
5348 static void
5349 output_attr(FILE *fp, struct zone_attrtab *attrtab)
5350 {
5351         (void) fprintf(fp, "%s:\n", rt_to_str(RT_ATTR));
5352         output_prop(fp, PT_NAME, attrtab->zone_attr_name, B_TRUE);
5353         output_prop(fp, PT_TYPE, attrtab->zone_attr_type, B_TRUE);
5354         output_prop(fp, PT_VALUE, attrtab->zone_attr_value, B_TRUE);
5355 }
5356 
5357 static void
5358 info_attr(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5359 {
5360         struct zone_attrtab lookup, user;
5361         boolean_t output = B_FALSE;
5362 
5363         if (zonecfg_setattrent(handle) != Z_OK)
5364                 return;
5365         while (zonecfg_getattrent(handle, &lookup) == Z_OK) {
5366                 if (cmd->cmd_prop_nv_pairs == 0) {
5367                         output_attr(fp, &lookup);
5368                         continue;
5369                 }
5370                 if (fill_in_attrtab(cmd, &user, B_TRUE) != Z_OK)
5371                         continue;
5372                 if (strlen(user.zone_attr_name) > 0 &&
5373                     strcmp(user.zone_attr_name, lookup.zone_attr_name) != 0)
5374                         continue;       /* no match */
5375                 if (strlen(user.zone_attr_type) > 0 &&
5376                     strcmp(user.zone_attr_type, lookup.zone_attr_type) != 0)
5377                         continue;       /* no match */
5378                 if (strlen(user.zone_attr_value) > 0 &&
5379                     strcmp(user.zone_attr_value, lookup.zone_attr_value) != 0)
5380                         continue;       /* no match */
5381                 output_attr(fp, &lookup);
5382                 output = B_TRUE;
5383         }
5384         (void) zonecfg_endattrent(handle);
5385         /*
5386          * If a property n/v pair was specified, warn the user if there was
5387          * nothing to output.
5388          */
5389         if (!output && cmd->cmd_prop_nv_pairs > 0)
5390                 (void) printf(gettext("No such %s resource.\n"),
5391                     rt_to_str(RT_ATTR));
5392 }
5393 
5394 static void
5395 output_ds(FILE *fp, struct zone_dstab *dstab)
5396 {
5397         (void) fprintf(fp, "%s:\n", rt_to_str(RT_DATASET));
5398         output_prop(fp, PT_NAME, dstab->zone_dataset_name, B_TRUE);
5399 }
5400 
5401 static void
5402 info_ds(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5403 {
5404         struct zone_dstab lookup, user;
5405         boolean_t output = B_FALSE;
5406 
5407         if (zonecfg_setdsent(handle) != Z_OK)
5408                 return;
5409         while (zonecfg_getdsent(handle, &lookup) == Z_OK) {
5410                 if (cmd->cmd_prop_nv_pairs == 0) {
5411                         output_ds(fp, &lookup);
5412                         continue;
5413                 }
5414                 if (fill_in_dstab(cmd, &user, B_TRUE) != Z_OK)
5415                         continue;
5416                 if (strlen(user.zone_dataset_name) > 0 &&
5417                     strcmp(user.zone_dataset_name,
5418                     lookup.zone_dataset_name) != 0)
5419                         continue;       /* no match */
5420                 output_ds(fp, &lookup);
5421                 output = B_TRUE;
5422         }
5423         (void) zonecfg_enddsent(handle);
5424         /*
5425          * If a property n/v pair was specified, warn the user if there was
5426          * nothing to output.
5427          */
5428         if (!output && cmd->cmd_prop_nv_pairs > 0)
5429                 (void) printf(gettext("No such %s resource.\n"),
5430                     rt_to_str(RT_DATASET));
5431 }
5432 
5433 static void
5434 output_pset(FILE *fp, struct zone_psettab *psettab)
5435 {
5436         (void) fprintf(fp, "%s:\n", rt_to_str(RT_DCPU));
5437         if (strcmp(psettab->zone_ncpu_min, psettab->zone_ncpu_max) == 0)
5438                 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_NCPUS),
5439                     psettab->zone_ncpu_max);
5440         else
5441                 (void) fprintf(fp, "\t%s: %s-%s\n", pt_to_str(PT_NCPUS),
5442                     psettab->zone_ncpu_min, psettab->zone_ncpu_max);
5443         if (psettab->zone_importance[0] != '\0')
5444                 (void) fprintf(fp, "\t%s: %s\n", pt_to_str(PT_IMPORTANCE),
5445                     psettab->zone_importance);
5446 }
5447 
5448 static void
5449 info_pset(zone_dochandle_t handle, FILE *fp)
5450 {
5451         struct zone_psettab lookup;
5452 
5453         if (zonecfg_getpsetent(handle, &lookup) == Z_OK)
5454                 output_pset(fp, &lookup);
5455 }
5456 
5457 static void
5458 output_pcap(FILE *fp)
5459 {
5460         uint64_t cap;
5461 
5462         if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &cap) == Z_OK) {
5463                 float scaled = (float)cap / 100;
5464                 (void) fprintf(fp, "%s:\n", rt_to_str(RT_PCAP));
5465                 (void) fprintf(fp, "\t[%s: %.2f]\n", pt_to_str(PT_NCPUS),
5466                     scaled);
5467         }
5468 }
5469 
5470 static void
5471 info_pcap(FILE *fp)
5472 {
5473         output_pcap(fp);
5474 }
5475 
5476 
5477 static void
5478 info_aliased_rctl(zone_dochandle_t handle, FILE *fp, char *alias)
5479 {
5480         uint64_t limit;
5481 
5482         if (zonecfg_get_aliased_rctl(handle, alias, &limit) == Z_OK) {
5483                 /* convert memory based properties */
5484                 if (strcmp(alias, ALIAS_MAXSHMMEM) == 0) {
5485                         char buf[128];
5486 
5487                         (void) snprintf(buf, sizeof (buf), "%llu", limit);
5488                         bytes_to_units(buf, buf, sizeof (buf));
5489                         (void) fprintf(fp, "[%s: %s]\n", alias, buf);
5490                         return;
5491                 }
5492 
5493                 (void) fprintf(fp, "[%s: %llu]\n", alias, limit);
5494         }
5495 }
5496 
5497 static void
5498 bytes_to_units(char *str, char *buf, int bufsize)
5499 {
5500         unsigned long long num;
5501         unsigned long long save = 0;
5502         char *units = "BKMGT";
5503         char *up = units;
5504 
5505         num = strtoll(str, NULL, 10);
5506 
5507         if (num < 1024) {
5508                 (void) snprintf(buf, bufsize, "%llu", num);
5509                 return;
5510         }
5511 
5512         while ((num >= 1024) && (*up != 'T')) {
5513                 up++; /* next unit of measurement */
5514                 save = num;
5515                 num = (num + 512) >> 10;
5516         }
5517 
5518         /* check if we should output a fraction.  snprintf will round for us */
5519         if (save % 1024 != 0 && ((save >> 10) < 10))
5520                 (void) snprintf(buf, bufsize, "%2.1f%c", ((float)save / 1024),
5521                     *up);
5522         else
5523                 (void) snprintf(buf, bufsize, "%llu%c", num, *up);
5524 }
5525 
5526 static void
5527 output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
5528     uint64_t maxswap, int showlocked, uint64_t maxlocked)
5529 {
5530         char buf[128];
5531 
5532         (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
5533         if (mcaptab->zone_physmem_cap[0] != '\0') {
5534                 bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
5535                 output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
5536         }
5537 
5538         if (showswap == Z_OK) {
5539                 (void) snprintf(buf, sizeof (buf), "%llu", maxswap);
5540                 bytes_to_units(buf, buf, sizeof (buf));
5541                 output_prop(fp, PT_SWAP, buf, B_TRUE);
5542         }
5543 
5544         if (showlocked == Z_OK) {
5545                 (void) snprintf(buf, sizeof (buf), "%llu", maxlocked);
5546                 bytes_to_units(buf, buf, sizeof (buf));
5547                 output_prop(fp, PT_LOCKED, buf, B_TRUE);
5548         }
5549 }
5550 
5551 static void
5552 info_mcap(zone_dochandle_t handle, FILE *fp)
5553 {
5554         int res1, res2, res3;
5555         uint64_t swap_limit;
5556         uint64_t locked_limit;
5557         struct zone_mcaptab lookup;
5558 
5559         bzero(&lookup, sizeof (lookup));
5560         res1 = zonecfg_getmcapent(handle, &lookup);
5561         res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
5562         res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
5563             &locked_limit);
5564 
5565         if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
5566                 output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
5567 }
5568 
5569 static void
5570 output_auth(FILE *fp, struct zone_admintab *admintab)
5571 {
5572         (void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN));
5573         output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE);
5574         output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE);
5575 }
5576 
5577 static void
5578 output_secflags(FILE *fp, struct zone_secflagstab *sftab)
5579 {
5580         (void) fprintf(fp, "%s:\n", rt_to_str(RT_SECFLAGS));
5581         output_prop(fp, PT_DEFAULT, sftab->zone_secflags_default, B_TRUE);
5582         output_prop(fp, PT_LOWER, sftab->zone_secflags_lower, B_TRUE);
5583         output_prop(fp, PT_UPPER, sftab->zone_secflags_upper, B_TRUE);
5584 }
5585 
5586 static void
5587 info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
5588 {
5589         struct zone_admintab lookup, user;
5590         boolean_t output = B_FALSE;
5591         int err;
5592 
5593         if ((err = zonecfg_setadminent(handle)) != Z_OK) {
5594                 zone_perror(zone, err, B_TRUE);
5595                 return;
5596         }
5597         while (zonecfg_getadminent(handle, &lookup) == Z_OK) {
5598                 if (cmd->cmd_prop_nv_pairs == 0) {
5599                         output_auth(fp, &lookup);
5600                         continue;
5601                 }
5602                 if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK)
5603                         continue;
5604                 if (strlen(user.zone_admin_user) > 0 &&
5605                     strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
5606                         continue;       /* no match */
5607                 output_auth(fp, &lookup);
5608                 output = B_TRUE;
5609         }
5610         (void) zonecfg_endadminent(handle);
5611         /*
5612          * If a property n/v pair was specified, warn the user if there was
5613          * nothing to output.
5614          */
5615         if (!output && cmd->cmd_prop_nv_pairs > 0)
5616                 (void) printf(gettext("No such %s resource.\n"),
5617                     rt_to_str(RT_ADMIN));
5618 }
5619 
5620 static void
5621 info_secflags(zone_dochandle_t handle, FILE *fp)
5622 {
5623         struct zone_secflagstab sftab;
5624 
5625         if (zonecfg_lookup_secflags(handle, &sftab) == Z_OK) {
5626                 output_secflags(fp, &sftab);
5627         }
5628 }
5629 
5630 void
5631 info_func(cmd_t *cmd)
5632 {
5633         FILE *fp = stdout;
5634         boolean_t need_to_close = B_FALSE;
5635         int type;
5636         int res1, res2;
5637         uint64_t swap_limit;
5638         uint64_t locked_limit;
5639 
5640         assert(cmd != NULL);
5641 
5642         if (initialize(B_TRUE) != Z_OK)
5643                 return;
5644 
5645         /* don't page error output */
5646         if (interactive_mode) {
5647                 if ((fp = pager_open()) != NULL)
5648                         need_to_close = B_TRUE;
5649                 else
5650                         fp = stdout;
5651 
5652                 setbuf(fp, NULL);
5653         }
5654 
5655         if (!global_scope) {
5656                 switch (resource_scope) {
5657                 case RT_FS:
5658                         output_fs(fp, &in_progress_fstab);
5659                         break;
5660                 case RT_NET:
5661                         output_net(fp, &in_progress_nwiftab);
5662                         break;
5663                 case RT_DEVICE:
5664                         output_dev(fp, &in_progress_devtab);
5665                         break;
5666                 case RT_RCTL:
5667                         output_rctl(fp, &in_progress_rctltab);
5668                         break;
5669                 case RT_ATTR:
5670                         output_attr(fp, &in_progress_attrtab);
5671                         break;
5672                 case RT_DATASET:
5673                         output_ds(fp, &in_progress_dstab);
5674                         break;
5675                 case RT_DCPU:
5676                         output_pset(fp, &in_progress_psettab);
5677                         break;
5678                 case RT_PCAP:
5679                         output_pcap(fp);
5680                         break;
5681                 case RT_MCAP:
5682                         res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
5683                             &swap_limit);
5684                         res2 = zonecfg_get_aliased_rctl(handle,
5685                             ALIAS_MAXLOCKEDMEM, &locked_limit);
5686                         output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
5687                             res2, locked_limit);
5688                         break;
5689                 case RT_ADMIN:
5690                         output_auth(fp, &in_progress_admintab);
5691                         break;
5692                 case RT_SECFLAGS:
5693                         output_secflags(fp, &in_progress_secflagstab);
5694                         break;
5695                 }
5696                 goto cleanup;
5697         }
5698 
5699         type = cmd->cmd_res_type;
5700 
5701         if (gz_invalid_rt_property(type)) {
5702                 zerr(gettext("%s is not a valid property for the global zone."),
5703                     rt_to_str(type));
5704                 goto cleanup;
5705         }
5706 
5707         if (gz_invalid_resource(type)) {
5708                 zerr(gettext("%s is not a valid resource for the global zone."),
5709                     rt_to_str(type));
5710                 goto cleanup;
5711         }
5712 
5713         switch (cmd->cmd_res_type) {
5714         case RT_UNKNOWN:
5715                 info_zonename(handle, fp);
5716                 if (!global_zone) {
5717                         info_zonepath(handle, fp);
5718                         info_brand(handle, fp);
5719                         info_autoboot(handle, fp);
5720                         info_bootargs(handle, fp);
5721                 }
5722                 info_pool(handle, fp);
5723                 if (!global_zone) {
5724                         info_limitpriv(handle, fp);
5725                         info_sched(handle, fp);
5726                         info_iptype(handle, fp);
5727                         info_hostid(handle, fp);
5728                         info_fs_allowed(handle, fp);
5729                 }
5730                 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5731                 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5732                 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5733                 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5734                 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5735                 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5736                 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5737                 if (!global_zone) {
5738                         info_fs(handle, fp, cmd);
5739                         info_net(handle, fp, cmd);
5740                         info_dev(handle, fp, cmd);
5741                 }
5742                 info_pset(handle, fp);
5743                 info_pcap(fp);
5744                 info_mcap(handle, fp);
5745                 if (!global_zone) {
5746                         info_attr(handle, fp, cmd);
5747                         info_ds(handle, fp, cmd);
5748                         info_auth(handle, fp, cmd);
5749                 }
5750                 info_rctl(handle, fp, cmd);
5751                 info_secflags(handle, fp);
5752                 break;
5753         case RT_ZONENAME:
5754                 info_zonename(handle, fp);
5755                 break;
5756         case RT_ZONEPATH:
5757                 info_zonepath(handle, fp);
5758                 break;
5759         case RT_BRAND:
5760                 info_brand(handle, fp);
5761                 break;
5762         case RT_AUTOBOOT:
5763                 info_autoboot(handle, fp);
5764                 break;
5765         case RT_POOL:
5766                 info_pool(handle, fp);
5767                 break;
5768         case RT_LIMITPRIV:
5769                 info_limitpriv(handle, fp);
5770                 break;
5771         case RT_BOOTARGS:
5772                 info_bootargs(handle, fp);
5773                 break;
5774         case RT_SCHED:
5775                 info_sched(handle, fp);
5776                 break;
5777         case RT_IPTYPE:
5778                 info_iptype(handle, fp);
5779                 break;
5780         case RT_MAXLWPS:
5781                 info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
5782                 break;
5783         case RT_MAXPROCS:
5784                 info_aliased_rctl(handle, fp, ALIAS_MAXPROCS);
5785                 break;
5786         case RT_MAXSHMMEM:
5787                 info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
5788                 break;
5789         case RT_MAXSHMIDS:
5790                 info_aliased_rctl(handle, fp, ALIAS_MAXSHMIDS);
5791                 break;
5792         case RT_MAXMSGIDS:
5793                 info_aliased_rctl(handle, fp, ALIAS_MAXMSGIDS);
5794                 break;
5795         case RT_MAXSEMIDS:
5796                 info_aliased_rctl(handle, fp, ALIAS_MAXSEMIDS);
5797                 break;
5798         case RT_SHARES:
5799                 info_aliased_rctl(handle, fp, ALIAS_SHARES);
5800                 break;
5801         case RT_FS:
5802                 info_fs(handle, fp, cmd);
5803                 break;
5804         case RT_NET:
5805                 info_net(handle, fp, cmd);
5806                 break;
5807         case RT_DEVICE:
5808                 info_dev(handle, fp, cmd);
5809                 break;
5810         case RT_RCTL:
5811                 info_rctl(handle, fp, cmd);
5812                 break;
5813         case RT_ATTR:
5814                 info_attr(handle, fp, cmd);
5815                 break;
5816         case RT_DATASET:
5817                 info_ds(handle, fp, cmd);
5818                 break;
5819         case RT_DCPU:
5820                 info_pset(handle, fp);
5821                 break;
5822         case RT_PCAP:
5823                 info_pcap(fp);
5824                 break;
5825         case RT_MCAP:
5826                 info_mcap(handle, fp);
5827                 break;
5828         case RT_HOSTID:
5829                 info_hostid(handle, fp);
5830                 break;
5831         case RT_ADMIN:
5832                 info_auth(handle, fp, cmd);
5833                 break;
5834         case RT_FS_ALLOWED:
5835                 info_fs_allowed(handle, fp);
5836                 break;
5837         case RT_SECFLAGS:
5838                 info_secflags(handle, fp);
5839                 break;
5840         default:
5841                 zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
5842                     B_TRUE);
5843         }
5844 
5845 cleanup:
5846         if (need_to_close)
5847                 (void) pager_close(fp);
5848 }
5849 
5850 /*
5851  * Helper function for verify-- checks that a required string property
5852  * exists.
5853  */
5854 static void
5855 check_reqd_prop(char *attr, int rt, int pt, int *ret_val)
5856 {
5857         if (strlen(attr) == 0) {
5858                 zerr(gettext("%s: %s not specified"), rt_to_str(rt),
5859                     pt_to_str(pt));
5860                 saw_error = B_TRUE;
5861                 if (*ret_val == Z_OK)
5862                         *ret_val = Z_REQD_PROPERTY_MISSING;
5863         }
5864 }
5865 
5866 static int
5867 do_subproc(char *cmdbuf)
5868 {
5869         char inbuf[MAX_CMD_LEN];
5870         FILE *file;
5871         int status;
5872 
5873         file = popen(cmdbuf, "r");
5874         if (file == NULL) {
5875                 zerr(gettext("Could not launch: %s"), cmdbuf);
5876                 return (-1);
5877         }
5878 
5879         while (fgets(inbuf, sizeof (inbuf), file) != NULL)
5880                 fprintf(stderr, "%s", inbuf);
5881         status = pclose(file);
5882 
5883         if (WIFSIGNALED(status)) {
5884                 zerr(gettext("%s unexpectedly terminated due to signal %d"),
5885                     cmdbuf, WTERMSIG(status));
5886                 return (-1);
5887         }
5888         assert(WIFEXITED(status));
5889         return (WEXITSTATUS(status));
5890 }
5891 
5892 static int
5893 brand_verify(zone_dochandle_t handle)
5894 {
5895         char xml_file[32];
5896         char cmdbuf[MAX_CMD_LEN];
5897         brand_handle_t bh;
5898         char brand[MAXNAMELEN];
5899         int err;
5900 
5901         if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
5902                 zerr("%s: %s\n", zone, gettext("could not get zone brand"));
5903                 return (Z_INVALID_DOCUMENT);
5904         }
5905         if ((bh = brand_open(brand)) == NULL) {
5906                 zerr("%s: %s\n", zone, gettext("unknown brand."));
5907                 return (Z_INVALID_DOCUMENT);
5908         }
5909 
5910         /*
5911          * Fetch the verify command, if any, from the brand configuration
5912          * and build the command line to execute it.
5913          */
5914         strcpy(cmdbuf, EXEC_PREFIX);
5915         err = brand_get_verify_cfg(bh, cmdbuf + EXEC_LEN,
5916             sizeof (cmdbuf) - (EXEC_LEN + (strlen(xml_file) + 1)));
5917         brand_close(bh);
5918         if (err != Z_OK) {
5919                 zerr("%s: %s\n", zone,
5920                     gettext("could not get brand verification command"));
5921                 return (Z_INVALID_DOCUMENT);
5922         }
5923 
5924         /*
5925          * If the brand doesn't provide a verification routine, we just
5926          * return success.
5927          */
5928         if (strlen(cmdbuf) == EXEC_LEN)
5929                 return (Z_OK);
5930 
5931         /*
5932          * Dump the current config information for this zone to a file.
5933          */
5934         strcpy(xml_file, "/tmp/zonecfg_verify.XXXXXX");
5935         if (mkstemp(xml_file) == NULL)
5936                 return (Z_TEMP_FILE);
5937         if ((err = zonecfg_verify_save(handle, xml_file)) != Z_OK) {
5938                 (void) unlink(xml_file);
5939                 return (err);
5940         }
5941 
5942         /*
5943          * Execute the verification command.
5944          */
5945         if ((strlcat(cmdbuf, " ", MAX_CMD_LEN) >= MAX_CMD_LEN) ||
5946             (strlcat(cmdbuf, xml_file, MAX_CMD_LEN) >= MAX_CMD_LEN)) {
5947                 err = Z_BRAND_ERROR;
5948         } else {
5949                 err = do_subproc(cmdbuf);
5950         }
5951 
5952         (void) unlink(xml_file);
5953         return ((err == Z_OK) ? Z_OK : Z_BRAND_ERROR);
5954 }
5955 
5956 /*
5957  * Track the network interfaces listed in zonecfg(1m) in a linked list
5958  * so that we can later check that defrouter is specified for an exclusive IP
5959  * zone if and only if at least one allowed-address has been specified.
5960  */
5961 static boolean_t
5962 add_nwif(struct zone_nwiftab *nwif)
5963 {
5964         struct xif *tmp;
5965 
5966         for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
5967                 if (strcmp(tmp->xif_name, nwif->zone_nwif_physical) == 0) {
5968                         if (strlen(nwif->zone_nwif_allowed_address) > 0)
5969                                 tmp->xif_has_address = B_TRUE;
5970                         if (strlen(nwif->zone_nwif_defrouter) > 0)
5971                                 tmp->xif_has_defrouter = B_TRUE;
5972                         return (B_TRUE);
5973                 }
5974         }
5975 
5976         tmp = malloc(sizeof (*tmp));
5977         if (tmp == NULL) {
5978                 zerr(gettext("memory allocation failed for %s"),
5979                     nwif->zone_nwif_physical);
5980                 return (B_FALSE);
5981         }
5982         strlcpy(tmp->xif_name, nwif->zone_nwif_physical,
5983             sizeof (tmp->xif_name));
5984         tmp->xif_has_defrouter = (strlen(nwif->zone_nwif_defrouter) > 0);
5985         tmp->xif_has_address = (strlen(nwif->zone_nwif_allowed_address) > 0);
5986         tmp->xif_next = xif;
5987         xif = tmp;
5988         return (B_TRUE);
5989 }
5990 
5991 boolean_t
5992 verify_secflags(struct zone_secflagstab *tab)
5993 {
5994         secflagdelta_t def = {0};
5995         secflagdelta_t upper = {0};
5996         secflagdelta_t lower = {0};
5997         boolean_t def_set = B_FALSE;
5998         boolean_t upper_set = B_FALSE;
5999         boolean_t lower_set = B_FALSE;
6000         boolean_t ret = B_TRUE;
6001 
6002         if (strlen(tab->zone_secflags_default) > 0) {
6003                 def_set = B_TRUE;
6004                 if (secflags_parse(NULL, tab->zone_secflags_default,
6005                     &def) == -1) {
6006                         zerr(gettext("default security flags '%s' are invalid"),
6007                             tab->zone_secflags_default);
6008                         ret = B_FALSE;
6009                 }
6010         } else {
6011                 secflags_zero(&def.psd_assign);
6012                 def.psd_ass_active = B_TRUE;
6013         }
6014 
6015         if (strlen(tab->zone_secflags_upper) > 0) {
6016                 upper_set = B_TRUE;
6017                 if (secflags_parse(NULL, tab->zone_secflags_upper,
6018                     &upper) == -1) {
6019                         zerr(gettext("upper security flags '%s' are invalid"),
6020                             tab->zone_secflags_upper);
6021                         ret = B_FALSE;
6022                 }
6023         } else {
6024                 secflags_fullset(&upper.psd_assign);
6025                 upper.psd_ass_active = B_TRUE;
6026         }
6027 
6028         if (strlen(tab->zone_secflags_lower) > 0) {
6029                 lower_set = B_TRUE;
6030                 if (secflags_parse(NULL, tab->zone_secflags_lower,
6031                     &lower) == -1) {
6032                         zerr(gettext("lower security flags '%s' are invalid"),
6033                             tab->zone_secflags_lower);
6034                         ret = B_FALSE;
6035                 }
6036         } else {
6037                 secflags_zero(&lower.psd_assign);
6038                 lower.psd_ass_active = B_TRUE;
6039         }
6040 
6041         if (def_set && !def.psd_ass_active) {
6042                 zerr(gettext("only assignment of security flags is "
6043                     "allowed (default: %s)"), tab->zone_secflags_default);
6044         }
6045 
6046         if (lower_set && !lower.psd_ass_active) {
6047                 zerr(gettext("only assignment of security flags is "
6048                     "allowed (lower: %s)"), tab->zone_secflags_lower);
6049         }
6050 
6051         if (upper_set && !upper.psd_ass_active) {
6052                 zerr(gettext("only assignment of security flags is "
6053                     "allowed (upper: %s)"), tab->zone_secflags_upper);
6054         }
6055 
6056         if (def.psd_assign & ~upper.psd_assign)     { /* In default but not upper */
6057                 zerr(gettext("default secflags must be within the "
6058                     "upper limit"));
6059                 ret = B_FALSE;
6060         }
6061         if (lower.psd_assign & ~def.psd_assign) { /* In lower but not default */
6062                 zerr(gettext("default secflags must be above the lower limit"));
6063                 ret = B_FALSE;
6064         }
6065         if (lower.psd_assign & ~upper.psd_assign) { /* In lower but not upper */
6066                 zerr(gettext("lower secflags must be within the upper limit"));
6067                 ret = B_FALSE;
6068         }
6069 
6070         return (ret);
6071 }
6072 
6073 /*
6074  * See the DTD for which attributes are required for which resources.
6075  *
6076  * This function can be called by commit_func(), which needs to save things,
6077  * in addition to the general call from parse_and_run(), which doesn't need
6078  * things saved.  Since the parameters are standardized, we distinguish by
6079  * having commit_func() call here with cmd->cmd_arg set to "save" to indicate
6080  * that a save is needed.
6081  */
6082 void
6083 verify_func(cmd_t *cmd)
6084 {
6085         struct zone_nwiftab nwiftab;
6086         struct zone_fstab fstab;
6087         struct zone_attrtab attrtab;
6088         struct zone_rctltab rctltab;
6089         struct zone_dstab dstab;
6090         struct zone_psettab psettab;
6091         struct zone_admintab admintab;
6092         struct zone_secflagstab secflagstab;
6093         char zonepath[MAXPATHLEN];
6094         char sched[MAXNAMELEN];
6095         char brand[MAXNAMELEN];
6096         char hostidp[HW_HOSTID_LEN];
6097         char fsallowedp[ZONE_FS_ALLOWED_MAX];
6098         priv_set_t *privs;
6099         char *privname = NULL;
6100         int err, ret_val = Z_OK, arg;
6101         int pset_res;
6102         boolean_t save = B_FALSE;
6103         boolean_t arg_err = B_FALSE;
6104         zone_iptype_t iptype;
6105         boolean_t has_cpu_shares = B_FALSE;
6106         boolean_t has_cpu_cap = B_FALSE;
6107         struct xif *tmp;
6108 
6109         optind = 0;
6110         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6111                 switch (arg) {
6112                 case '?':
6113                         longer_usage(CMD_VERIFY);
6114                         arg_err = B_TRUE;
6115                         break;
6116                 default:
6117                         short_usage(CMD_VERIFY);
6118                         arg_err = B_TRUE;
6119                         break;
6120                 }
6121         }
6122         if (arg_err)
6123                 return;
6124 
6125         if (optind > cmd->cmd_argc) {
6126                 short_usage(CMD_VERIFY);
6127                 return;
6128         }
6129 
6130         if (zone_is_read_only(CMD_VERIFY))
6131                 return;
6132 
6133         assert(cmd != NULL);
6134 
6135         if (cmd->cmd_argc > 0 && (strcmp(cmd->cmd_argv[0], "save") == 0))
6136                 save = B_TRUE;
6137         if (initialize(B_TRUE) != Z_OK)
6138                 return;
6139 
6140         if (zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)) != Z_OK &&
6141             !global_zone) {
6142                 zerr(gettext("%s not specified"), pt_to_str(PT_ZONEPATH));
6143                 ret_val = Z_REQD_RESOURCE_MISSING;
6144                 saw_error = B_TRUE;
6145         }
6146         if (strlen(zonepath) == 0 && !global_zone) {
6147                 zerr(gettext("%s cannot be empty."), pt_to_str(PT_ZONEPATH));
6148                 ret_val = Z_REQD_RESOURCE_MISSING;
6149                 saw_error = B_TRUE;
6150         }
6151 
6152         if ((err = zonecfg_get_brand(handle, brand, sizeof (brand))) != Z_OK) {
6153                 zone_perror(zone, err, B_TRUE);
6154                 return;
6155         }
6156         if ((err = brand_verify(handle)) != Z_OK) {
6157                 zone_perror(zone, err, B_TRUE);
6158                 return;
6159         }
6160 
6161         if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
6162                 zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
6163                 ret_val = Z_REQD_RESOURCE_MISSING;
6164                 saw_error = B_TRUE;
6165         }
6166 
6167         if ((privs = priv_allocset()) == NULL) {
6168                 zerr(gettext("%s: priv_allocset failed"), zone);
6169                 return;
6170         }
6171         if (zonecfg_get_privset(handle, privs, &privname) != Z_OK) {
6172                 zerr(gettext("%s: invalid privilege: %s"), zone, privname);
6173                 priv_freeset(privs);
6174                 free(privname);
6175                 return;
6176         }
6177         priv_freeset(privs);
6178 
6179         if (zonecfg_get_hostid(handle, hostidp,
6180             sizeof (hostidp)) == Z_INVALID_PROPERTY) {
6181                 zerr(gettext("%s: invalid hostid: %s"),
6182                     zone, hostidp);
6183                 return;
6184         }
6185 
6186         if (zonecfg_get_fs_allowed(handle, fsallowedp,
6187             sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
6188                 zerr(gettext("%s: invalid fs-allowed: %s"),
6189                     zone, fsallowedp);
6190                 return;
6191         }
6192 
6193         if ((err = zonecfg_setfsent(handle)) != Z_OK) {
6194                 zone_perror(zone, err, B_TRUE);
6195                 return;
6196         }
6197         while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
6198                 check_reqd_prop(fstab.zone_fs_dir, RT_FS, PT_DIR, &ret_val);
6199                 check_reqd_prop(fstab.zone_fs_special, RT_FS, PT_SPECIAL,
6200                     &ret_val);
6201                 check_reqd_prop(fstab.zone_fs_type, RT_FS, PT_TYPE, &ret_val);
6202 
6203                 zonecfg_free_fs_option_list(fstab.zone_fs_options);
6204         }
6205         (void) zonecfg_endfsent(handle);
6206 
6207         if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
6208                 zone_perror(zone, err, B_TRUE);
6209                 return;
6210         }
6211         while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
6212                 /*
6213                  * physical is required in all cases.
6214                  * A shared IP requires an address,
6215                  * and may include a default router, while
6216                  * an exclusive IP must have neither an address
6217                  * nor a default router.
6218                  * The physical interface name must be valid in all cases.
6219                  */
6220                 check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
6221                     PT_PHYSICAL, &ret_val);
6222                 if (validate_net_physical_syntax(nwiftab.zone_nwif_physical) !=
6223                     Z_OK) {
6224                         saw_error = B_TRUE;
6225                         if (ret_val == Z_OK)
6226                                 ret_val = Z_INVAL;
6227                 }
6228 
6229                 switch (iptype) {
6230                 case ZS_SHARED:
6231                         check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
6232                             PT_ADDRESS, &ret_val);
6233                         if (strlen(nwiftab.zone_nwif_allowed_address) > 0) {
6234                                 zerr(gettext("%s: %s cannot be specified "
6235                                     "for a shared IP type"),
6236                                     rt_to_str(RT_NET),
6237                                     pt_to_str(PT_ALLOWED_ADDRESS));
6238                                 saw_error = B_TRUE;
6239                                 if (ret_val == Z_OK)
6240                                         ret_val = Z_INVAL;
6241                         }
6242                         break;
6243                 case ZS_EXCLUSIVE:
6244                         if (strlen(nwiftab.zone_nwif_address) > 0) {
6245                                 zerr(gettext("%s: %s cannot be specified "
6246                                     "for an exclusive IP type"),
6247                                     rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
6248                                 saw_error = B_TRUE;
6249                                 if (ret_val == Z_OK)
6250                                         ret_val = Z_INVAL;
6251                         } else {
6252                                 if (!add_nwif(&nwiftab)) {
6253                                         saw_error = B_TRUE;
6254                                         if (ret_val == Z_OK)
6255                                                 ret_val = Z_INVAL;
6256                                 }
6257                         }
6258                         break;
6259                 }
6260         }
6261         for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
6262                 if (!tmp->xif_has_address && tmp->xif_has_defrouter) {
6263                         zerr(gettext("%s: %s for %s cannot be specified "
6264                             "without %s for an exclusive IP type"),
6265                             rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER),
6266                             tmp->xif_name, pt_to_str(PT_ALLOWED_ADDRESS));
6267                         saw_error = B_TRUE;
6268                         ret_val = Z_INVAL;
6269                 }
6270         }
6271         free(xif);
6272         xif = NULL;
6273         (void) zonecfg_endnwifent(handle);
6274 
6275         if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
6276                 zone_perror(zone, err, B_TRUE);
6277                 return;
6278         }
6279         while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
6280                 check_reqd_prop(rctltab.zone_rctl_name, RT_RCTL, PT_NAME,
6281                     &ret_val);
6282 
6283                 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-shares") == 0)
6284                         has_cpu_shares = B_TRUE;
6285 
6286                 if (strcmp(rctltab.zone_rctl_name, "zone.cpu-cap") == 0)
6287                         has_cpu_cap = B_TRUE;
6288 
6289                 if (rctltab.zone_rctl_valptr == NULL) {
6290                         zerr(gettext("%s: no %s specified"),
6291                             rt_to_str(RT_RCTL), pt_to_str(PT_VALUE));
6292                         saw_error = B_TRUE;
6293                         if (ret_val == Z_OK)
6294                                 ret_val = Z_REQD_PROPERTY_MISSING;
6295                 } else {
6296                         zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
6297                 }
6298         }
6299         (void) zonecfg_endrctlent(handle);
6300 
6301         if ((pset_res = zonecfg_lookup_pset(handle, &psettab)) == Z_OK &&
6302             has_cpu_shares) {
6303                 zerr(gettext("%s zone.cpu-shares and %s are incompatible."),
6304                     rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6305                 saw_error = B_TRUE;
6306                 if (ret_val == Z_OK)
6307                         ret_val = Z_INCOMPATIBLE;
6308         }
6309 
6310         if (has_cpu_shares && zonecfg_get_sched_class(handle, sched,
6311             sizeof (sched)) == Z_OK && strlen(sched) > 0 &&
6312             strcmp(sched, "FSS") != 0) {
6313                 zerr(gettext("WARNING: %s zone.cpu-shares and %s=%s are "
6314                     "incompatible"),
6315                     rt_to_str(RT_RCTL), rt_to_str(RT_SCHED), sched);
6316                 saw_error = B_TRUE;
6317                 if (ret_val == Z_OK)
6318                         ret_val = Z_INCOMPATIBLE;
6319         }
6320 
6321         if (pset_res == Z_OK && has_cpu_cap) {
6322                 zerr(gettext("%s zone.cpu-cap and the %s are incompatible."),
6323                     rt_to_str(RT_RCTL), rt_to_str(RT_DCPU));
6324                 saw_error = B_TRUE;
6325                 if (ret_val == Z_OK)
6326                         ret_val = Z_INCOMPATIBLE;
6327         }
6328 
6329         if ((err = zonecfg_setattrent(handle)) != Z_OK) {
6330                 zone_perror(zone, err, B_TRUE);
6331                 return;
6332         }
6333         while (zonecfg_getattrent(handle, &attrtab) == Z_OK) {
6334                 check_reqd_prop(attrtab.zone_attr_name, RT_ATTR, PT_NAME,
6335                     &ret_val);
6336                 check_reqd_prop(attrtab.zone_attr_type, RT_ATTR, PT_TYPE,
6337                     &ret_val);
6338                 check_reqd_prop(attrtab.zone_attr_value, RT_ATTR, PT_VALUE,
6339                     &ret_val);
6340         }
6341         (void) zonecfg_endattrent(handle);
6342 
6343         if ((err = zonecfg_setdsent(handle)) != Z_OK) {
6344                 zone_perror(zone, err, B_TRUE);
6345                 return;
6346         }
6347         while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
6348                 if (strlen(dstab.zone_dataset_name) == 0) {
6349                         zerr("%s: %s %s", rt_to_str(RT_DATASET),
6350                             pt_to_str(PT_NAME), gettext("not specified"));
6351                         saw_error = B_TRUE;
6352                         if (ret_val == Z_OK)
6353                                 ret_val = Z_REQD_PROPERTY_MISSING;
6354                 } else if (!zfs_name_valid(dstab.zone_dataset_name,
6355                     ZFS_TYPE_FILESYSTEM)) {
6356                         zerr("%s: %s %s", rt_to_str(RT_DATASET),
6357                             pt_to_str(PT_NAME), gettext("invalid"));
6358                         saw_error = B_TRUE;
6359                         if (ret_val == Z_OK)
6360                                 ret_val = Z_BAD_PROPERTY;
6361                 }
6362 
6363         }
6364         (void) zonecfg_enddsent(handle);
6365 
6366         if ((err = zonecfg_setadminent(handle)) != Z_OK) {
6367                 zone_perror(zone, err, B_TRUE);
6368                 return;
6369         }
6370         while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
6371                 check_reqd_prop(admintab.zone_admin_user, RT_ADMIN,
6372                     PT_USER, &ret_val);
6373                 check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN,
6374                     PT_AUTHS, &ret_val);
6375                 if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user)
6376                     == NULL)) {
6377                         zerr(gettext("%s %s is not a valid username"),
6378                             pt_to_str(PT_USER),
6379                             admintab.zone_admin_user);
6380                         ret_val = Z_BAD_PROPERTY;
6381                 }
6382                 if ((ret_val == Z_OK) && (!zonecfg_valid_auths(
6383                     admintab.zone_admin_auths, zone))) {
6384                         ret_val = Z_BAD_PROPERTY;
6385                 }
6386         }
6387         (void) zonecfg_endadminent(handle);
6388 
6389         if (zonecfg_getsecflagsent(handle, &secflagstab) == Z_OK) {
6390                 /*
6391                  * No properties are required, but any specified should be
6392                  * valid
6393                  */
6394                 if (verify_secflags(&secflagstab) != B_TRUE) {
6395                         /* Error is reported from verify_secflags */
6396                         ret_val = Z_BAD_PROPERTY;
6397                 }
6398         }
6399 
6400         if (!global_scope) {
6401                 zerr(gettext("resource specification incomplete"));
6402                 saw_error = B_TRUE;
6403                 if (ret_val == Z_OK)
6404                         ret_val = Z_INSUFFICIENT_SPEC;
6405         }
6406 
6407         if (save) {
6408                 if (ret_val == Z_OK) {
6409                         if ((ret_val = zonecfg_save(handle)) == Z_OK) {
6410                                 need_to_commit = B_FALSE;
6411                                 (void) strlcpy(revert_zone, zone,
6412                                     sizeof (revert_zone));
6413                         }
6414                 } else {
6415                         zerr(gettext("Zone %s failed to verify"), zone);
6416                 }
6417         }
6418         if (ret_val != Z_OK)
6419                 zone_perror(zone, ret_val, B_TRUE);
6420 }
6421 
6422 void
6423 cancel_func(cmd_t *cmd)
6424 {
6425         int arg;
6426         boolean_t arg_err = B_FALSE;
6427 
6428         assert(cmd != NULL);
6429 
6430         optind = 0;
6431         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6432                 switch (arg) {
6433                 case '?':
6434                         longer_usage(CMD_CANCEL);
6435                         arg_err = B_TRUE;
6436                         break;
6437                 default:
6438                         short_usage(CMD_CANCEL);
6439                         arg_err = B_TRUE;
6440                         break;
6441                 }
6442         }
6443         if (arg_err)
6444                 return;
6445 
6446         if (optind != cmd->cmd_argc) {
6447                 short_usage(CMD_CANCEL);
6448                 return;
6449         }
6450 
6451         if (global_scope)
6452                 scope_usage(CMD_CANCEL);
6453         global_scope = B_TRUE;
6454         zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6455         bzero(&in_progress_fstab, sizeof (in_progress_fstab));
6456         bzero(&in_progress_nwiftab, sizeof (in_progress_nwiftab));
6457         bzero(&in_progress_devtab, sizeof (in_progress_devtab));
6458         zonecfg_free_rctl_value_list(in_progress_rctltab.zone_rctl_valptr);
6459         bzero(&in_progress_rctltab, sizeof (in_progress_rctltab));
6460         bzero(&in_progress_attrtab, sizeof (in_progress_attrtab));
6461         bzero(&in_progress_dstab, sizeof (in_progress_dstab));
6462 }
6463 
6464 static int
6465 validate_attr_name(char *name)
6466 {
6467         int i;
6468 
6469         if (!isalnum(name[0])) {
6470                 zerr(gettext("Invalid %s %s %s: must start with an alpha-"
6471                     "numeric character."), rt_to_str(RT_ATTR),
6472                     pt_to_str(PT_NAME), name);
6473                 return (Z_INVAL);
6474         }
6475         for (i = 1; name[i]; i++)
6476                 if (!isalnum(name[i]) && name[i] != '-' && name[i] != '.') {
6477                         zerr(gettext("Invalid %s %s %s: can only contain "
6478                             "alpha-numeric characters, plus '-' and '.'."),
6479                             rt_to_str(RT_ATTR), pt_to_str(PT_NAME), name);
6480                         return (Z_INVAL);
6481                 }
6482         return (Z_OK);
6483 }
6484 
6485 static int
6486 validate_attr_type_val(struct zone_attrtab *attrtab)
6487 {
6488         boolean_t boolval;
6489         int64_t intval;
6490         char strval[MAXNAMELEN];
6491         uint64_t uintval;
6492 
6493         if (strcmp(attrtab->zone_attr_type, "boolean") == 0) {
6494                 if (zonecfg_get_attr_boolean(attrtab, &boolval) == Z_OK)
6495                         return (Z_OK);
6496                 zerr(gettext("invalid %s value for %s=%s"),
6497                     rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "boolean");
6498                 return (Z_ERR);
6499         }
6500 
6501         if (strcmp(attrtab->zone_attr_type, "int") == 0) {
6502                 if (zonecfg_get_attr_int(attrtab, &intval) == Z_OK)
6503                         return (Z_OK);
6504                 zerr(gettext("invalid %s value for %s=%s"),
6505                     rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "int");
6506                 return (Z_ERR);
6507         }
6508 
6509         if (strcmp(attrtab->zone_attr_type, "string") == 0) {
6510                 if (zonecfg_get_attr_string(attrtab, strval,
6511                     sizeof (strval)) == Z_OK)
6512                         return (Z_OK);
6513                 zerr(gettext("invalid %s value for %s=%s"),
6514                     rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "string");
6515                 return (Z_ERR);
6516         }
6517 
6518         if (strcmp(attrtab->zone_attr_type, "uint") == 0) {
6519                 if (zonecfg_get_attr_uint(attrtab, &uintval) == Z_OK)
6520                         return (Z_OK);
6521                 zerr(gettext("invalid %s value for %s=%s"),
6522                     rt_to_str(RT_ATTR), pt_to_str(PT_TYPE), "uint");
6523                 return (Z_ERR);
6524         }
6525 
6526         zerr(gettext("invalid %s %s '%s'"), rt_to_str(RT_ATTR),
6527             pt_to_str(PT_TYPE), attrtab->zone_attr_type);
6528         return (Z_ERR);
6529 }
6530 
6531 /*
6532  * Helper function for end_func-- checks the existence of a given property
6533  * and emits a message if not specified.
6534  */
6535 static int
6536 end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
6537 {
6538         if (strlen(attr) == 0) {
6539                 *validation_failed = B_TRUE;
6540                 zerr(gettext("%s not specified"), pt_to_str(pt));
6541                 return (Z_ERR);
6542         }
6543         return (Z_OK);
6544 }
6545 
6546 static void
6547 net_exists_error(struct zone_nwiftab nwif)
6548 {
6549         if (strlen(nwif.zone_nwif_address) > 0) {
6550                 zerr(gettext("A %s resource with the %s '%s', "
6551                     "and %s '%s' already exists."),
6552                     rt_to_str(RT_NET),
6553                     pt_to_str(PT_PHYSICAL),
6554                     nwif.zone_nwif_physical,
6555                     pt_to_str(PT_ADDRESS),
6556                     in_progress_nwiftab.zone_nwif_address);
6557         } else {
6558                 zerr(gettext("A %s resource with the %s '%s', "
6559                     "and %s '%s' already exists."),
6560                     rt_to_str(RT_NET),
6561                     pt_to_str(PT_PHYSICAL),
6562                     nwif.zone_nwif_physical,
6563                     pt_to_str(PT_ALLOWED_ADDRESS),
6564                     nwif.zone_nwif_allowed_address);
6565         }
6566 }
6567 
6568 void
6569 end_func(cmd_t *cmd)
6570 {
6571         boolean_t validation_failed = B_FALSE;
6572         boolean_t arg_err = B_FALSE;
6573         struct zone_fstab tmp_fstab;
6574         struct zone_nwiftab tmp_nwiftab;
6575         struct zone_devtab tmp_devtab;
6576         struct zone_rctltab tmp_rctltab;
6577         struct zone_attrtab tmp_attrtab;
6578         struct zone_dstab tmp_dstab;
6579         struct zone_admintab tmp_admintab;
6580         int err, arg, res1, res2, res3;
6581         uint64_t swap_limit;
6582         uint64_t locked_limit;
6583         uint64_t proc_cap;
6584 
6585         assert(cmd != NULL);
6586 
6587         optind = 0;
6588         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
6589                 switch (arg) {
6590                 case '?':
6591                         longer_usage(CMD_END);
6592                         arg_err = B_TRUE;
6593                         break;
6594                 default:
6595                         short_usage(CMD_END);
6596                         arg_err = B_TRUE;
6597                         break;
6598                 }
6599         }
6600         if (arg_err)
6601                 return;
6602 
6603         if (optind != cmd->cmd_argc) {
6604                 short_usage(CMD_END);
6605                 return;
6606         }
6607 
6608         if (global_scope) {
6609                 scope_usage(CMD_END);
6610                 return;
6611         }
6612 
6613         assert(end_op == CMD_ADD || end_op == CMD_SELECT);
6614 
6615         switch (resource_scope) {
6616         case RT_FS:
6617                 /* First make sure everything was filled in. */
6618                 if (end_check_reqd(in_progress_fstab.zone_fs_dir,
6619                     PT_DIR, &validation_failed) == Z_OK) {
6620                         if (in_progress_fstab.zone_fs_dir[0] != '/') {
6621                                 zerr(gettext("%s %s is not an absolute path."),
6622                                     pt_to_str(PT_DIR),
6623                                     in_progress_fstab.zone_fs_dir);
6624                                 validation_failed = B_TRUE;
6625                         }
6626                 }
6627 
6628                 (void) end_check_reqd(in_progress_fstab.zone_fs_special,
6629                     PT_SPECIAL, &validation_failed);
6630 
6631                 if (in_progress_fstab.zone_fs_raw[0] != '\0' &&
6632                     in_progress_fstab.zone_fs_raw[0] != '/') {
6633                         zerr(gettext("%s %s is not an absolute path."),
6634                             pt_to_str(PT_RAW),
6635                             in_progress_fstab.zone_fs_raw);
6636                         validation_failed = B_TRUE;
6637                 }
6638 
6639                 (void) end_check_reqd(in_progress_fstab.zone_fs_type, PT_TYPE,
6640                     &validation_failed);
6641 
6642                 if (validation_failed) {
6643                         saw_error = B_TRUE;
6644                         return;
6645                 }
6646 
6647                 if (end_op == CMD_ADD) {
6648                         /* Make sure there isn't already one like this. */
6649                         bzero(&tmp_fstab, sizeof (tmp_fstab));
6650                         (void) strlcpy(tmp_fstab.zone_fs_dir,
6651                             in_progress_fstab.zone_fs_dir,
6652                             sizeof (tmp_fstab.zone_fs_dir));
6653                         err = zonecfg_lookup_filesystem(handle, &tmp_fstab);
6654                         zonecfg_free_fs_option_list(tmp_fstab.zone_fs_options);
6655                         if (err == Z_OK) {
6656                                 zerr(gettext("A %s resource "
6657                                     "with the %s '%s' already exists."),
6658                                     rt_to_str(RT_FS), pt_to_str(PT_DIR),
6659                                     in_progress_fstab.zone_fs_dir);
6660                                 saw_error = B_TRUE;
6661                                 return;
6662                         }
6663                         err = zonecfg_add_filesystem(handle,
6664                             &in_progress_fstab);
6665                 } else {
6666                         err = zonecfg_modify_filesystem(handle, &old_fstab,
6667                             &in_progress_fstab);
6668                 }
6669                 zonecfg_free_fs_option_list(in_progress_fstab.zone_fs_options);
6670                 in_progress_fstab.zone_fs_options = NULL;
6671                 break;
6672 
6673         case RT_NET:
6674                 /*
6675                  * First make sure everything was filled in.
6676                  * Since we don't know whether IP will be shared
6677                  * or exclusive here, some checks are deferred until
6678                  * the verify command.
6679                  */
6680                 (void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
6681                     PT_PHYSICAL, &validation_failed);
6682 
6683                 if (validation_failed) {
6684                         saw_error = B_TRUE;
6685                         return;
6686                 }
6687                 if (end_op == CMD_ADD) {
6688                         /* Make sure there isn't already one like this. */
6689                         bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
6690                         (void) strlcpy(tmp_nwiftab.zone_nwif_physical,
6691                             in_progress_nwiftab.zone_nwif_physical,
6692                             sizeof (tmp_nwiftab.zone_nwif_physical));
6693                         (void) strlcpy(tmp_nwiftab.zone_nwif_address,
6694                             in_progress_nwiftab.zone_nwif_address,
6695                             sizeof (tmp_nwiftab.zone_nwif_address));
6696                         (void) strlcpy(tmp_nwiftab.zone_nwif_allowed_address,
6697                             in_progress_nwiftab.zone_nwif_allowed_address,
6698                             sizeof (tmp_nwiftab.zone_nwif_allowed_address));
6699                         (void) strlcpy(tmp_nwiftab.zone_nwif_defrouter,
6700                             in_progress_nwiftab.zone_nwif_defrouter,
6701                             sizeof (tmp_nwiftab.zone_nwif_defrouter));
6702                         if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
6703                                 net_exists_error(in_progress_nwiftab);
6704                                 saw_error = B_TRUE;
6705                                 return;
6706                         }
6707                         err = zonecfg_add_nwif(handle, &in_progress_nwiftab);
6708                 } else {
6709                         err = zonecfg_modify_nwif(handle, &old_nwiftab,
6710                             &in_progress_nwiftab);
6711                 }
6712                 break;
6713 
6714         case RT_DEVICE:
6715                 /* First make sure everything was filled in. */
6716                 (void) end_check_reqd(in_progress_devtab.zone_dev_match,
6717                     PT_MATCH, &validation_failed);
6718 
6719                 if (validation_failed) {
6720                         saw_error = B_TRUE;
6721                         return;
6722                 }
6723 
6724                 if (end_op == CMD_ADD) {
6725                         /* Make sure there isn't already one like this. */
6726                         (void) strlcpy(tmp_devtab.zone_dev_match,
6727                             in_progress_devtab.zone_dev_match,
6728                             sizeof (tmp_devtab.zone_dev_match));
6729                         if (zonecfg_lookup_dev(handle, &tmp_devtab) == Z_OK) {
6730                                 zerr(gettext("A %s resource with the %s '%s' "
6731                                     "already exists."), rt_to_str(RT_DEVICE),
6732                                     pt_to_str(PT_MATCH),
6733                                     in_progress_devtab.zone_dev_match);
6734                                 saw_error = B_TRUE;
6735                                 return;
6736                         }
6737                         err = zonecfg_add_dev(handle, &in_progress_devtab);
6738                 } else {
6739                         err = zonecfg_modify_dev(handle, &old_devtab,
6740                             &in_progress_devtab);
6741                 }
6742                 break;
6743 
6744         case RT_RCTL:
6745                 /* First make sure everything was filled in. */
6746                 (void) end_check_reqd(in_progress_rctltab.zone_rctl_name,
6747                     PT_NAME, &validation_failed);
6748 
6749                 if (in_progress_rctltab.zone_rctl_valptr == NULL) {
6750                         zerr(gettext("no %s specified"), pt_to_str(PT_VALUE));
6751                         validation_failed = B_TRUE;
6752                 }
6753 
6754                 if (validation_failed) {
6755                         saw_error = B_TRUE;
6756                         return;
6757                 }
6758 
6759                 if (end_op == CMD_ADD) {
6760                         /* Make sure there isn't already one like this. */
6761                         (void) strlcpy(tmp_rctltab.zone_rctl_name,
6762                             in_progress_rctltab.zone_rctl_name,
6763                             sizeof (tmp_rctltab.zone_rctl_name));
6764                         tmp_rctltab.zone_rctl_valptr = NULL;
6765                         err = zonecfg_lookup_rctl(handle, &tmp_rctltab);
6766                         zonecfg_free_rctl_value_list(
6767                             tmp_rctltab.zone_rctl_valptr);
6768                         if (err == Z_OK) {
6769                                 zerr(gettext("A %s resource "
6770                                     "with the %s '%s' already exists."),
6771                                     rt_to_str(RT_RCTL), pt_to_str(PT_NAME),
6772                                     in_progress_rctltab.zone_rctl_name);
6773                                 saw_error = B_TRUE;
6774                                 return;
6775                         }
6776                         err = zonecfg_add_rctl(handle, &in_progress_rctltab);
6777                 } else {
6778                         err = zonecfg_modify_rctl(handle, &old_rctltab,
6779                             &in_progress_rctltab);
6780                 }
6781                 if (err == Z_OK) {
6782                         zonecfg_free_rctl_value_list(
6783                             in_progress_rctltab.zone_rctl_valptr);
6784                         in_progress_rctltab.zone_rctl_valptr = NULL;
6785                 }
6786                 break;
6787 
6788         case RT_ATTR:
6789                 /* First make sure everything was filled in. */
6790                 (void) end_check_reqd(in_progress_attrtab.zone_attr_name,
6791                     PT_NAME, &validation_failed);
6792                 (void) end_check_reqd(in_progress_attrtab.zone_attr_type,
6793                     PT_TYPE, &validation_failed);
6794                 (void) end_check_reqd(in_progress_attrtab.zone_attr_value,
6795                     PT_VALUE, &validation_failed);
6796 
6797                 if (validate_attr_name(in_progress_attrtab.zone_attr_name) !=
6798                     Z_OK)
6799                         validation_failed = B_TRUE;
6800 
6801                 if (validate_attr_type_val(&in_progress_attrtab) != Z_OK)
6802                         validation_failed = B_TRUE;
6803 
6804                 if (validation_failed) {
6805                         saw_error = B_TRUE;
6806                         return;
6807                 }
6808                 if (end_op == CMD_ADD) {
6809                         /* Make sure there isn't already one like this. */
6810                         bzero(&tmp_attrtab, sizeof (tmp_attrtab));
6811                         (void) strlcpy(tmp_attrtab.zone_attr_name,
6812                             in_progress_attrtab.zone_attr_name,
6813                             sizeof (tmp_attrtab.zone_attr_name));
6814                         if (zonecfg_lookup_attr(handle, &tmp_attrtab) == Z_OK) {
6815                                 zerr(gettext("An %s resource "
6816                                     "with the %s '%s' already exists."),
6817                                     rt_to_str(RT_ATTR), pt_to_str(PT_NAME),
6818                                     in_progress_attrtab.zone_attr_name);
6819                                 saw_error = B_TRUE;
6820                                 return;
6821                         }
6822                         err = zonecfg_add_attr(handle, &in_progress_attrtab);
6823                 } else {
6824                         err = zonecfg_modify_attr(handle, &old_attrtab,
6825                             &in_progress_attrtab);
6826                 }
6827                 break;
6828         case RT_DATASET:
6829                 /* First make sure everything was filled in. */
6830                 if (strlen(in_progress_dstab.zone_dataset_name) == 0) {
6831                         zerr("%s %s", pt_to_str(PT_NAME),
6832                             gettext("not specified"));
6833                         saw_error = B_TRUE;
6834                         validation_failed = B_TRUE;
6835                 }
6836                 if (validation_failed)
6837                         return;
6838                 if (end_op == CMD_ADD) {
6839                         /* Make sure there isn't already one like this. */
6840                         bzero(&tmp_dstab, sizeof (tmp_dstab));
6841                         (void) strlcpy(tmp_dstab.zone_dataset_name,
6842                             in_progress_dstab.zone_dataset_name,
6843                             sizeof (tmp_dstab.zone_dataset_name));
6844                         err = zonecfg_lookup_ds(handle, &tmp_dstab);
6845                         if (err == Z_OK) {
6846                                 zerr(gettext("A %s resource "
6847                                     "with the %s '%s' already exists."),
6848                                     rt_to_str(RT_DATASET), pt_to_str(PT_NAME),
6849                                     in_progress_dstab.zone_dataset_name);
6850                                 saw_error = B_TRUE;
6851                                 return;
6852                         }
6853                         err = zonecfg_add_ds(handle, &in_progress_dstab);
6854                 } else {
6855                         err = zonecfg_modify_ds(handle, &old_dstab,
6856                             &in_progress_dstab);
6857                 }
6858                 break;
6859         case RT_DCPU:
6860                 /* Make sure everything was filled in. */
6861                 if (end_check_reqd(in_progress_psettab.zone_ncpu_min,
6862                     PT_NCPUS, &validation_failed) != Z_OK) {
6863                         saw_error = B_TRUE;
6864                         return;
6865                 }
6866 
6867                 if (end_op == CMD_ADD) {
6868                         err = zonecfg_add_pset(handle, &in_progress_psettab);
6869                 } else {
6870                         err = zonecfg_modify_pset(handle, &in_progress_psettab);
6871                 }
6872                 break;
6873         case RT_PCAP:
6874                 /* Make sure everything was filled in. */
6875                 if (zonecfg_get_aliased_rctl(handle, ALIAS_CPUCAP, &proc_cap)
6876                     != Z_OK) {
6877                         zerr(gettext("%s not specified"), pt_to_str(PT_NCPUS));
6878                         saw_error = B_TRUE;
6879                         validation_failed = B_TRUE;
6880                         return;
6881                 }
6882                 err = Z_OK;
6883                 break;
6884         case RT_MCAP:
6885                 /* Make sure everything was filled in. */
6886                 res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
6887                     Z_ERR : Z_OK;
6888                 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
6889                     &swap_limit);
6890                 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
6891                     &locked_limit);
6892 
6893                 if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
6894                         zerr(gettext("No property was specified.  One of %s, "
6895                             "%s or %s is required."), pt_to_str(PT_PHYSICAL),
6896                             pt_to_str(PT_SWAP), pt_to_str(PT_LOCKED));
6897                         saw_error = B_TRUE;
6898                         return;
6899                 }
6900 
6901                 /* if phys & locked are both set, verify locked <= phys */
6902                 if (res1 == Z_OK && res3 == Z_OK) {
6903                         uint64_t phys_limit;
6904                         char *endp;
6905 
6906                         phys_limit = strtoull(
6907                             in_progress_mcaptab.zone_physmem_cap, &endp, 10);
6908                         if (phys_limit < locked_limit) {
6909                                 zerr(gettext("The %s cap must be less than or "
6910                                     "equal to the %s cap."),
6911                                     pt_to_str(PT_LOCKED),
6912                                     pt_to_str(PT_PHYSICAL));
6913                                 saw_error = B_TRUE;
6914                                 return;
6915                         }
6916                 }
6917 
6918                 err = Z_OK;
6919                 if (res1 == Z_OK) {
6920                         /*
6921                          * We could be ending from either an add operation
6922                          * or a select operation.  Since all of the properties
6923                          * within this resource are optional, we always use
6924                          * modify on the mcap entry.  zonecfg_modify_mcap()
6925                          * will handle both adding and modifying a memory cap.
6926                          */
6927                         err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
6928                 } else if (end_op == CMD_SELECT) {
6929                         /*
6930                          * If we're ending from a select and the physical
6931                          * memory cap is empty then the user could have cleared
6932                          * the physical cap value, so try to delete the entry.
6933                          */
6934                         (void) zonecfg_delete_mcap(handle);
6935                 }
6936                 break;
6937         case RT_ADMIN:
6938                 /* First make sure everything was filled in. */
6939                 if (end_check_reqd(in_progress_admintab.zone_admin_user,
6940                     PT_USER, &validation_failed) == Z_OK) {
6941                         if (getpwnam(in_progress_admintab.zone_admin_user)
6942                             == NULL) {
6943                                 zerr(gettext("%s %s is not a valid username"),
6944                                     pt_to_str(PT_USER),
6945                                     in_progress_admintab.zone_admin_user);
6946                                 validation_failed = B_TRUE;
6947                         }
6948                 }
6949 
6950                 if (end_check_reqd(in_progress_admintab.zone_admin_auths,
6951                     PT_AUTHS, &validation_failed) == Z_OK) {
6952                         if (!zonecfg_valid_auths(
6953                             in_progress_admintab.zone_admin_auths,
6954                             zone)) {
6955                                 validation_failed = B_TRUE;
6956                         }
6957                 }
6958 
6959                 if (validation_failed) {
6960                         saw_error = B_TRUE;
6961                         return;
6962                 }
6963 
6964                 if (end_op == CMD_ADD) {
6965                         /* Make sure there isn't already one like this. */
6966                         bzero(&tmp_admintab, sizeof (tmp_admintab));
6967                         (void) strlcpy(tmp_admintab.zone_admin_user,
6968                             in_progress_admintab.zone_admin_user,
6969                             sizeof (tmp_admintab.zone_admin_user));
6970                         err = zonecfg_lookup_admin(
6971                             handle, &tmp_admintab);
6972                         if (err == Z_OK) {
6973                                 zerr(gettext("A %s resource "
6974                                     "with the %s '%s' already exists."),
6975                                     rt_to_str(RT_ADMIN),
6976                                     pt_to_str(PT_USER),
6977                                     in_progress_admintab.zone_admin_user);
6978                                 saw_error = B_TRUE;
6979                                 return;
6980                         }
6981                         err = zonecfg_add_admin(handle,
6982                             &in_progress_admintab, zone);
6983                 } else {
6984                         err = zonecfg_modify_admin(handle,
6985                             &old_admintab, &in_progress_admintab,
6986                             zone);
6987                 }
6988                 break;
6989         case RT_SECFLAGS:
6990                 if (verify_secflags(&in_progress_secflagstab) != B_TRUE) {
6991                         saw_error = B_TRUE;
6992                         return;
6993                 }
6994 
6995                 if (end_op == CMD_ADD) {
6996                         err = zonecfg_add_secflags(handle,
6997                             &in_progress_secflagstab);
6998                 } else {
6999                         err = zonecfg_modify_secflags(handle,
7000                             &old_secflagstab, &in_progress_secflagstab);
7001                 }
7002                 break;
7003         default:
7004                 zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
7005                     B_TRUE);
7006                 saw_error = B_TRUE;
7007                 return;
7008         }
7009 
7010         if (err != Z_OK) {
7011                 zone_perror(zone, err, B_TRUE);
7012         } else {
7013                 need_to_commit = B_TRUE;
7014                 global_scope = B_TRUE;
7015                 end_op = -1;
7016         }
7017 }
7018 
7019 void
7020 commit_func(cmd_t *cmd)
7021 {
7022         int arg;
7023         boolean_t arg_err = B_FALSE;
7024 
7025         optind = 0;
7026         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
7027                 switch (arg) {
7028                 case '?':
7029                         longer_usage(CMD_COMMIT);
7030                         arg_err = B_TRUE;
7031                         break;
7032                 default:
7033                         short_usage(CMD_COMMIT);
7034                         arg_err = B_TRUE;
7035                         break;
7036                 }
7037         }
7038         if (arg_err)
7039                 return;
7040 
7041         if (optind != cmd->cmd_argc) {
7042                 short_usage(CMD_COMMIT);
7043                 return;
7044         }
7045 
7046         if (zone_is_read_only(CMD_COMMIT))
7047                 return;
7048 
7049         assert(cmd != NULL);
7050 
7051         cmd->cmd_argc = 1;
7052         /*
7053          * cmd_arg normally comes from a strdup() in the lexer, and the
7054          * whole cmd structure and its (char *) attributes are freed at
7055          * the completion of each command, so the strdup() below is needed
7056          * to match this and prevent a core dump from trying to free()
7057          * something that can't be.
7058          */
7059         if ((cmd->cmd_argv[0] = strdup("save")) == NULL) {
7060                 zone_perror(zone, Z_NOMEM, B_TRUE);
7061                 exit(Z_ERR);
7062         }
7063         cmd->cmd_argv[1] = NULL;
7064         verify_func(cmd);
7065 }
7066 
7067 void
7068 revert_func(cmd_t *cmd)
7069 {
7070         char line[128]; /* enough to ask a question */
7071         boolean_t force = B_FALSE;
7072         boolean_t arg_err = B_FALSE;
7073         int err, arg, answer;
7074 
7075         optind = 0;
7076         while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?F")) != EOF) {
7077                 switch (arg) {
7078                 case '?':
7079                         longer_usage(CMD_REVERT);
7080                         arg_err = B_TRUE;
7081                         break;
7082                 case 'F':
7083                         force = B_TRUE;
7084                         break;
7085                 default:
7086                         short_usage(CMD_REVERT);
7087                         arg_err = B_TRUE;
7088                         break;
7089                 }
7090         }
7091         if (arg_err)
7092                 return;
7093 
7094         if (optind != cmd->cmd_argc) {
7095                 short_usage(CMD_REVERT);
7096                 return;
7097         }
7098 
7099         if (zone_is_read_only(CMD_REVERT))
7100                 return;
7101 
7102         if (!global_scope) {
7103                 zerr(gettext("You can only use %s in the global scope.\nUse"
7104                     " '%s' to cancel changes to a resource specification."),
7105                     cmd_to_str(CMD_REVERT), cmd_to_str(CMD_CANCEL));
7106                 saw_error = B_TRUE;
7107                 return;
7108         }
7109 
7110         if (zonecfg_check_handle(handle) != Z_OK) {
7111                 zerr(gettext("No changes to revert."));
7112                 saw_error = B_TRUE;
7113                 return;
7114         }
7115 
7116         if (!force) {
7117                 (void) snprintf(line, sizeof (line),
7118                     gettext("Are you sure you want to revert"));
7119                 if ((answer = ask_yesno(B_FALSE, line)) == -1) {
7120                         zerr(gettext("Input not from terminal and -F not "
7121                             "specified:\n%s command ignored, exiting."),
7122                             cmd_to_str(CMD_REVERT));
7123                         exit(Z_ERR);
7124                 }
7125                 if (answer != 1)
7126                         return;
7127         }
7128 
7129         /*
7130          * Reset any pending admins that were
7131          * removed from the previous zone
7132          */
7133         zonecfg_remove_userauths(handle, "", zone, B_FALSE);
7134 
7135         /*
7136          * Time for a new handle: finish the old one off first
7137          * then get a new one properly to avoid leaks.
7138          */
7139         zonecfg_fini_handle(handle);
7140         if ((handle = zonecfg_init_handle()) == NULL) {
7141                 zone_perror(execname, Z_NOMEM, B_TRUE);
7142                 exit(Z_ERR);
7143         }
7144 
7145         if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
7146                 saw_error = B_TRUE;
7147                 got_handle = B_FALSE;
7148                 if (err == Z_NO_ZONE)
7149                         zerr(gettext("%s: no such saved zone to revert to."),
7150                             revert_zone);
7151                 else
7152                         zone_perror(zone, err, B_TRUE);
7153         }
7154         (void) strlcpy(zone, revert_zone, sizeof (zone));
7155 }
7156 
7157 void
7158 help_func(cmd_t *cmd)
7159 {
7160         int i;
7161 
7162         assert(cmd != NULL);
7163 
7164         if (cmd->cmd_argc == 0) {
7165                 usage(B_TRUE, global_scope ? HELP_SUBCMDS : HELP_RES_SCOPE);
7166                 return;
7167         }
7168         if (strcmp(cmd->cmd_argv[0], "usage") == 0) {
7169                 usage(B_TRUE, HELP_USAGE);
7170                 return;
7171         }
7172         if (strcmp(cmd->cmd_argv[0], "commands") == 0) {
7173                 usage(B_TRUE, HELP_SUBCMDS);
7174                 return;
7175         }
7176         if (strcmp(cmd->cmd_argv[0], "syntax") == 0) {
7177                 usage(B_TRUE, HELP_SYNTAX | HELP_RES_PROPS);
7178                 return;
7179         }
7180         if (strcmp(cmd->cmd_argv[0], "-?") == 0) {
7181                 longer_usage(CMD_HELP);
7182                 return;
7183         }
7184 
7185         for (i = 0; i <= CMD_MAX; i++) {
7186                 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
7187                         longer_usage(i);
7188                         return;
7189                 }
7190         }
7191         /* We do not use zerr() here because we do not want its extra \n. */
7192         (void) fprintf(stderr, gettext("Unknown help subject %s.  "),
7193             cmd->cmd_argv[0]);
7194         usage(B_FALSE, HELP_META);
7195 }
7196 
7197 static int
7198 string_to_yyin(char *string)
7199 {
7200         if ((yyin = tmpfile()) == NULL) {
7201                 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7202                 return (Z_ERR);
7203         }
7204         if (fwrite(string, strlen(string), 1, yyin) != 1) {
7205                 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7206                 return (Z_ERR);
7207         }
7208         if (fseek(yyin, 0, SEEK_SET) != 0) {
7209                 zone_perror(execname, Z_TEMP_FILE, B_TRUE);
7210                 return (Z_ERR);
7211         }
7212         return (Z_OK);
7213 }
7214 
7215 /* This is the back-end helper function for read_input() below. */
7216 
7217 static int
7218 cleanup()
7219 {
7220         int answer;
7221         cmd_t *cmd;
7222 
7223         if (!interactive_mode && !cmd_file_mode) {
7224                 /*
7225                  * If we're not in interactive mode, and we're not in command
7226                  * file mode, then we must be in commands-from-the-command-line
7227                  * mode.  As such, we can't loop back and ask for more input.
7228                  * It was OK to prompt for such things as whether or not to
7229                  * really delete a zone in the command handler called from
7230                  * yyparse() above, but "really quit?" makes no sense in this
7231                  * context.  So disable prompting.
7232                  */
7233                 ok_to_prompt = B_FALSE;
7234         }
7235         if (!global_scope) {
7236                 if (!time_to_exit) {
7237                         /*
7238                          * Just print a simple error message in the -1 case,
7239                          * since exit_func() already handles that case, and
7240                          * EOF means we are finished anyway.
7241                          */
7242                         answer = ask_yesno(B_FALSE,
7243                             gettext("Resource incomplete; really quit"));
7244                         if (answer == -1) {
7245                                 zerr(gettext("Resource incomplete."));
7246                                 return (Z_ERR);
7247                         }
7248                         if (answer != 1) {
7249                                 yyin = stdin;
7250                                 return (Z_REPEAT);
7251                         }
7252                 } else {
7253                         saw_error = B_TRUE;
7254                 }
7255         }
7256         /*
7257          * Make sure we tried something and that the handle checks
7258          * out, or we would get a false error trying to commit.
7259          */
7260         if (need_to_commit && zonecfg_check_handle(handle) == Z_OK) {
7261                 if ((cmd = alloc_cmd()) == NULL) {
7262                         zone_perror(zone, Z_NOMEM, B_TRUE);
7263                         return (Z_ERR);
7264                 }
7265                 cmd->cmd_argc = 0;
7266                 cmd->cmd_argv[0] = NULL;
7267                 commit_func(cmd);
7268                 free_cmd(cmd);
7269                 /*
7270                  * need_to_commit will get set back to FALSE if the
7271                  * configuration is saved successfully.
7272                  */
7273                 if (need_to_commit) {
7274                         if (force_exit) {
7275                                 zerr(gettext("Configuration not saved."));
7276                                 return (Z_ERR);
7277                         }
7278                         answer = ask_yesno(B_FALSE,
7279                             gettext("Configuration not saved; really quit"));
7280                         if (answer == -1) {
7281                                 zerr(gettext("Configuration not saved."));
7282                                 return (Z_ERR);
7283                         }
7284                         if (answer != 1) {
7285                                 time_to_exit = B_FALSE;
7286                                 yyin = stdin;
7287                                 return (Z_REPEAT);
7288                         }
7289                 }
7290         }
7291         return ((need_to_commit || saw_error) ? Z_ERR : Z_OK);
7292 }
7293 
7294 /*
7295  * read_input() is the driver of this program.  It is a wrapper around
7296  * yyparse(), printing appropriate prompts when needed, checking for
7297  * exit conditions and reacting appropriately [the latter in its cleanup()
7298  * helper function].
7299  *
7300  * Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
7301  * so do_interactive() knows that we are not really done (i.e, we asked
7302  * the user if we should really quit and the user said no).
7303  */
7304 static int
7305 read_input()
7306 {
7307         boolean_t yyin_is_a_tty = isatty(fileno(yyin));
7308         /*
7309          * The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
7310          * and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
7311          */
7312         char prompt[MAXPATHLEN + ZONENAME_MAX + MAX_RT_STRLEN + 5], *line;
7313 
7314         /* yyin should have been set to the appropriate (FILE *) if not stdin */
7315         newline_terminated = B_TRUE;
7316         for (;;) {
7317                 if (yyin_is_a_tty) {
7318                         if (newline_terminated) {
7319                                 if (global_scope)
7320                                         (void) snprintf(prompt, sizeof (prompt),
7321                                             "%s:%s> ", execname, zone);
7322                                 else
7323                                         (void) snprintf(prompt, sizeof (prompt),
7324                                             "%s:%s:%s> ", execname, zone,
7325                                             rt_to_str(resource_scope));
7326                         }
7327                         /*
7328                          * If the user hits ^C then we want to catch it and
7329                          * start over.  If the user hits EOF then we want to
7330                          * bail out.
7331                          */
7332                         line = gl_get_line(gl, prompt, NULL, -1);
7333                         if (gl_return_status(gl) == GLR_SIGNAL) {
7334                                 gl_abandon_line(gl);
7335                                 continue;
7336                         }
7337                         if (line == NULL)
7338                                 break;
7339                         (void) string_to_yyin(line);
7340                         while (!feof(yyin))
7341                                 yyparse();
7342                 } else {
7343                         yyparse();
7344                 }
7345                 /* Bail out on an error in command file mode. */
7346                 if (saw_error && cmd_file_mode && !interactive_mode)
7347                         time_to_exit = B_TRUE;
7348                 if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
7349                         break;
7350         }
7351         return (cleanup());
7352 }
7353 
7354 /*
7355  * This function is used in the zonecfg-interactive-mode scenario: it just
7356  * calls read_input() until we are done.
7357  */
7358 
7359 static int
7360 do_interactive(void)
7361 {
7362         int err;
7363 
7364         interactive_mode = B_TRUE;
7365         if (!read_only_mode) {
7366                 /*
7367                  * Try to set things up proactively in interactive mode, so
7368                  * that if the zone in question does not exist yet, we can
7369                  * provide the user with a clue.
7370                  */
7371                 (void) initialize(B_FALSE);
7372         }
7373         do {
7374                 err = read_input();
7375         } while (err == Z_REPEAT);
7376         return (err);
7377 }
7378 
7379 /*
7380  * cmd_file is slightly more complicated, as it has to open the command file
7381  * and set yyin appropriately.  Once that is done, though, it just calls
7382  * read_input(), and only once, since prompting is not possible.
7383  */
7384 
7385 static int
7386 cmd_file(char *file)
7387 {
7388         FILE *infile;
7389         int err;
7390         struct stat statbuf;
7391         boolean_t using_real_file = (strcmp(file, "-") != 0);
7392 
7393         if (using_real_file) {
7394                 /*
7395                  * zerr() prints a line number in cmd_file_mode, which we do
7396                  * not want here, so temporarily unset it.
7397                  */
7398                 cmd_file_mode = B_FALSE;
7399                 if ((infile = fopen(file, "r")) == NULL) {
7400                         zerr(gettext("could not open file %s: %s"),
7401                             file, strerror(errno));
7402                         return (Z_ERR);
7403                 }
7404                 if ((err = fstat(fileno(infile), &statbuf)) != 0) {
7405                         zerr(gettext("could not stat file %s: %s"),
7406                             file, strerror(errno));
7407                         err = Z_ERR;
7408                         goto done;
7409                 }
7410                 if (!S_ISREG(statbuf.st_mode)) {
7411                         zerr(gettext("%s is not a regular file."), file);
7412                         err = Z_ERR;
7413                         goto done;
7414                 }
7415                 yyin = infile;
7416                 cmd_file_mode = B_TRUE;
7417                 ok_to_prompt = B_FALSE;
7418         } else {
7419                 /*
7420                  * "-f -" is essentially the same as interactive mode,
7421                  * so treat it that way.
7422                  */
7423                 interactive_mode = B_TRUE;
7424         }
7425         /* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
7426         if ((err = read_input()) == Z_REPEAT)
7427                 err = Z_ERR;
7428 done:
7429         if (using_real_file)
7430                 (void) fclose(infile);
7431         return (err);
7432 }
7433 
7434 /*
7435  * Since yacc is based on reading from a (FILE *) whereas what we get from
7436  * the command line is in argv format, we need to convert when the user
7437  * gives us commands directly from the command line.  That is done here by
7438  * concatenating the argv list into a space-separated string, writing it
7439  * to a temp file, and rewinding the file so yyin can be set to it.  Then
7440  * we call read_input(), and only once, since prompting about whether to
7441  * continue or quit would make no sense in this context.
7442  */
7443 
7444 static int
7445 one_command_at_a_time(int argc, char *argv[])
7446 {
7447         char *command;
7448         size_t len = 2; /* terminal \n\0 */
7449         int i, err;
7450 
7451         for (i = 0; i < argc; i++)
7452                 len += strlen(argv[i]) + 1;
7453         if ((command = malloc(len)) == NULL) {
7454                 zone_perror(execname, Z_NOMEM, B_TRUE);
7455                 return (Z_ERR);
7456         }
7457         (void) strlcpy(command, argv[0], len);
7458         for (i = 1; i < argc; i++) {
7459                 (void) strlcat(command, " ", len);
7460                 (void) strlcat(command, argv[i], len);
7461         }
7462         (void) strlcat(command, "\n", len);
7463         err = string_to_yyin(command);
7464         free(command);
7465         if (err != Z_OK)
7466                 return (err);
7467         while (!feof(yyin))
7468                 yyparse();
7469         return (cleanup());
7470 }
7471 
7472 static char *
7473 get_execbasename(char *execfullname)
7474 {
7475         char *last_slash, *execbasename;
7476 
7477         /* guard against '/' at end of command invocation */
7478         for (;;) {
7479                 last_slash = strrchr(execfullname, '/');
7480                 if (last_slash == NULL) {
7481                         execbasename = execfullname;
7482                         break;
7483                 } else {
7484                         execbasename = last_slash + 1;
7485                         if (*execbasename == '\0') {
7486                                 *last_slash = '\0';
7487                                 continue;
7488                         }
7489                         break;
7490                 }
7491         }
7492         return (execbasename);
7493 }
7494 
7495 int
7496 main(int argc, char *argv[])
7497 {
7498         int err, arg;
7499         struct stat st;
7500 
7501         /* This must be before anything goes to stdout. */
7502         setbuf(stdout, NULL);
7503 
7504         saw_error = B_FALSE;
7505         cmd_file_mode = B_FALSE;
7506         execname = get_execbasename(argv[0]);
7507 
7508         (void) setlocale(LC_ALL, "");
7509         (void) textdomain(TEXT_DOMAIN);
7510 
7511         if (getzoneid() != GLOBAL_ZONEID) {
7512                 zerr(gettext("%s can only be run from the global zone."),
7513                     execname);
7514                 exit(Z_ERR);
7515         }
7516 
7517         if (argc < 2) {
7518                 usage(B_FALSE, HELP_USAGE | HELP_SUBCMDS);
7519                 exit(Z_USAGE);
7520         }
7521         if (strcmp(argv[1], cmd_to_str(CMD_HELP)) == 0) {
7522                 (void) one_command_at_a_time(argc - 1, &(argv[1]));
7523                 exit(Z_OK);
7524         }
7525 
7526         while ((arg = getopt(argc, argv, "?f:R:z:")) != EOF) {
7527                 switch (arg) {
7528                 case '?':
7529                         if (optopt == '?')
7530                                 usage(B_TRUE, HELP_USAGE | HELP_SUBCMDS);
7531                         else
7532                                 usage(B_FALSE, HELP_USAGE);
7533                         exit(Z_USAGE);
7534                         /* NOTREACHED */
7535                 case 'f':
7536                         cmd_file_name = optarg;
7537                         cmd_file_mode = B_TRUE;
7538                         break;
7539                 case 'R':
7540                         if (*optarg != '/') {
7541                                 zerr(gettext("root path must be absolute: %s"),
7542                                     optarg);
7543                                 exit(Z_USAGE);
7544                         }
7545                         if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
7546                                 zerr(gettext(
7547                                     "root path must be a directory: %s"),
7548                                     optarg);
7549                                 exit(Z_USAGE);
7550                         }
7551                         zonecfg_set_root(optarg);
7552                         break;
7553                 case 'z':
7554                         if (strcmp(optarg, GLOBAL_ZONENAME) == 0) {
7555                                 global_zone = B_TRUE;
7556                         } else if (zonecfg_validate_zonename(optarg) != Z_OK) {
7557                                 zone_perror(optarg, Z_BOGUS_ZONE_NAME, B_TRUE);
7558                                 usage(B_FALSE, HELP_SYNTAX);
7559                                 exit(Z_USAGE);
7560                         }
7561                         (void) strlcpy(zone, optarg, sizeof (zone));
7562                         (void) strlcpy(revert_zone, optarg, sizeof (zone));
7563                         break;
7564                 default:
7565                         usage(B_FALSE, HELP_USAGE);
7566                         exit(Z_USAGE);
7567                 }
7568         }
7569 
7570         if (optind > argc || strcmp(zone, "") == 0) {
7571                 usage(B_FALSE, HELP_USAGE);
7572                 exit(Z_USAGE);
7573         }
7574 
7575         if ((err = zonecfg_access(zone, W_OK)) == Z_OK) {
7576                 read_only_mode = B_FALSE;
7577         } else if (err == Z_ACCES) {
7578                 read_only_mode = B_TRUE;
7579                 /* skip this message in one-off from command line mode */
7580                 if (optind == argc)
7581                         (void) fprintf(stderr, gettext("WARNING: you do not "
7582                             "have write access to this zone's configuration "
7583                             "file;\ngoing into read-only mode.\n"));
7584         } else {
7585                 fprintf(stderr, "%s: Could not access zone configuration "
7586                     "store: %s\n", execname, zonecfg_strerror(err));
7587                 exit(Z_ERR);
7588         }
7589 
7590         if ((handle = zonecfg_init_handle()) == NULL) {
7591                 zone_perror(execname, Z_NOMEM, B_TRUE);
7592                 exit(Z_ERR);
7593         }
7594 
7595         /*
7596          * This may get set back to FALSE again in cmd_file() if cmd_file_name
7597          * is a "real" file as opposed to "-" (i.e. meaning use stdin).
7598          */
7599         if (isatty(STDIN_FILENO))
7600                 ok_to_prompt = B_TRUE;
7601         if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
7602                 exit(Z_ERR);
7603         if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
7604                 exit(Z_ERR);
7605         (void) sigset(SIGINT, SIG_IGN);
7606         if (optind == argc) {
7607                 if (!cmd_file_mode)
7608                         err = do_interactive();
7609                 else
7610                         err = cmd_file(cmd_file_name);
7611         } else {
7612                 err = one_command_at_a_time(argc - optind, &(argv[optind]));
7613         }
7614         zonecfg_fini_handle(handle);
7615         if (brand != NULL)
7616                 brand_close(brand);
7617         (void) del_GetLine(gl);
7618         return (err);
7619 }