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