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