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