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 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * zoneadm is a command interpreter for zone administration.  It is all in
  29  * C (i.e., no lex/yacc), and all the argument passing is argc/argv based.
  30  * main() calls parse_and_run() which calls cmd_match(), then invokes the
  31  * appropriate command's handler function.  The rest of the program is the
  32  * handler functions and their helper functions.
  33  *
  34  * Some of the helper functions are used largely to simplify I18N: reducing
  35  * the need for translation notes.  This is particularly true of many of
  36  * the zerror() calls: doing e.g. zerror(gettext("%s failed"), "foo") rather
  37  * than zerror(gettext("foo failed")) with a translation note indicating
  38  * that "foo" need not be translated.
  39  */
  40 
  41 #include <stdio.h>
  42 #include <errno.h>
  43 #include <unistd.h>
  44 #include <signal.h>
  45 #include <stdarg.h>
  46 #include <ctype.h>
  47 #include <stdlib.h>
  48 #include <string.h>
  49 #include <wait.h>
  50 #include <zone.h>
  51 #include <priv.h>
  52 #include <locale.h>
  53 #include <libintl.h>
  54 #include <libzonecfg.h>
  55 #include <bsm/adt.h>
  56 #include <sys/brand.h>
  57 #include <sys/param.h>
  58 #include <sys/types.h>
  59 #include <sys/stat.h>
  60 #include <sys/statvfs.h>
  61 #include <assert.h>
  62 #include <sys/sockio.h>
  63 #include <sys/mntent.h>
  64 #include <limits.h>
  65 #include <dirent.h>
  66 #include <uuid/uuid.h>
  67 #include <libdlpi.h>
  68 
  69 #include <fcntl.h>
  70 #include <door.h>
  71 #include <macros.h>
  72 #include <libgen.h>
  73 #include <fnmatch.h>
  74 #include <sys/modctl.h>
  75 #include <libbrand.h>
  76 #include <libscf.h>
  77 #include <procfs.h>
  78 #include <strings.h>
  79 
  80 #include <pool.h>
  81 #include <sys/pool.h>
  82 #include <sys/priocntl.h>
  83 #include <sys/fsspriocntl.h>
  84 
  85 #include "zoneadm.h"
  86 
  87 #define MAXARGS 8
  88 
  89 /* Reflects kernel zone entries */
  90 typedef struct zone_entry {
  91         zoneid_t        zid;
  92         char            zname[ZONENAME_MAX];
  93         char            *zstate_str;
  94         zone_state_t    zstate_num;
  95         char            zbrand[MAXNAMELEN];
  96         char            zroot[MAXPATHLEN];
  97         char            zuuid[UUID_PRINTABLE_STRING_LENGTH];
  98         zone_iptype_t   ziptype;
  99 } zone_entry_t;
 100 
 101 #define CLUSTER_BRAND_NAME      "cluster"
 102 
 103 static zone_entry_t *zents;
 104 static size_t nzents;
 105 static boolean_t is_native_zone = B_TRUE;
 106 
 107 #define LOOPBACK_IF     "lo0"
 108 #define SOCKET_AF(af)   (((af) == AF_UNSPEC) ? AF_INET : (af))
 109 
 110 struct net_if {
 111         char    *name;
 112         int     af;
 113 };
 114 
 115 /* 0755 is the default directory mode. */
 116 #define DEFAULT_DIR_MODE \
 117         (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
 118 
 119 struct cmd {
 120         uint_t  cmd_num;                                /* command number */
 121         char    *cmd_name;                              /* command name */
 122         char    *short_usage;                           /* short form help */
 123         int     (*handler)(int argc, char *argv[]);     /* function to call */
 124 
 125 };
 126 
 127 #define SHELP_HELP      "help"
 128 #define SHELP_BOOT      "boot [-- boot_arguments]"
 129 #define SHELP_HALT      "halt"
 130 #define SHELP_READY     "ready"
 131 #define SHELP_REBOOT    "reboot [-- boot_arguments]"
 132 #define SHELP_LIST      "list [-cipv]"
 133 #define SHELP_VERIFY    "verify"
 134 #define SHELP_INSTALL   "install [-x nodataset] [brand-specific args]"
 135 #define SHELP_UNINSTALL "uninstall [-F] [brand-specific args]"
 136 #define SHELP_CLONE     "clone [-m method] [-s <ZFS snapshot>] "\
 137         "[brand-specific args] zonename"
 138 #define SHELP_MOVE      "move zonepath"
 139 #define SHELP_DETACH    "detach [-n] [brand-specific args]"
 140 #define SHELP_ATTACH    "attach [-F] [-n <path>] [brand-specific args]"
 141 #define SHELP_MARK      "mark incomplete"
 142 
 143 #define EXEC_PREFIX     "exec "
 144 #define EXEC_LEN        (strlen(EXEC_PREFIX))
 145 #define RMCOMMAND       "/usr/bin/rm -rf"
 146 
 147 static int cleanup_zonepath(char *, boolean_t);
 148 
 149 
 150 static int help_func(int argc, char *argv[]);
 151 static int ready_func(int argc, char *argv[]);
 152 static int boot_func(int argc, char *argv[]);
 153 static int halt_func(int argc, char *argv[]);
 154 static int reboot_func(int argc, char *argv[]);
 155 static int list_func(int argc, char *argv[]);
 156 static int verify_func(int argc, char *argv[]);
 157 static int install_func(int argc, char *argv[]);
 158 static int uninstall_func(int argc, char *argv[]);
 159 static int mount_func(int argc, char *argv[]);
 160 static int unmount_func(int argc, char *argv[]);
 161 static int clone_func(int argc, char *argv[]);
 162 static int move_func(int argc, char *argv[]);
 163 static int detach_func(int argc, char *argv[]);
 164 static int attach_func(int argc, char *argv[]);
 165 static int mark_func(int argc, char *argv[]);
 166 static int apply_func(int argc, char *argv[]);
 167 static int sanity_check(char *zone, int cmd_num, boolean_t running,
 168     boolean_t unsafe_when_running, boolean_t force);
 169 static int cmd_match(char *cmd);
 170 static int verify_details(int, char *argv[]);
 171 static int verify_brand(zone_dochandle_t, int, char *argv[]);
 172 static int invoke_brand_handler(int, char *argv[]);
 173 
 174 static struct cmd cmdtab[] = {
 175         { CMD_HELP,             "help",         SHELP_HELP,     help_func },
 176         { CMD_BOOT,             "boot",         SHELP_BOOT,     boot_func },
 177         { CMD_HALT,             "halt",         SHELP_HALT,     halt_func },
 178         { CMD_READY,            "ready",        SHELP_READY,    ready_func },
 179         { CMD_REBOOT,           "reboot",       SHELP_REBOOT,   reboot_func },
 180         { CMD_LIST,             "list",         SHELP_LIST,     list_func },
 181         { CMD_VERIFY,           "verify",       SHELP_VERIFY,   verify_func },
 182         { CMD_INSTALL,          "install",      SHELP_INSTALL,  install_func },
 183         { CMD_UNINSTALL,        "uninstall",    SHELP_UNINSTALL,
 184             uninstall_func },
 185         /* mount and unmount are private commands for admin/install */
 186         { CMD_MOUNT,            "mount",        NULL,           mount_func },
 187         { CMD_UNMOUNT,          "unmount",      NULL,           unmount_func },
 188         { CMD_CLONE,            "clone",        SHELP_CLONE,    clone_func },
 189         { CMD_MOVE,             "move",         SHELP_MOVE,     move_func },
 190         { CMD_DETACH,           "detach",       SHELP_DETACH,   detach_func },
 191         { CMD_ATTACH,           "attach",       SHELP_ATTACH,   attach_func },
 192         { CMD_MARK,             "mark",         SHELP_MARK,     mark_func },
 193         { CMD_APPLY,            "apply",        NULL,           apply_func }
 194 };
 195 
 196 /* global variables */
 197 
 198 /* set early in main(), never modified thereafter, used all over the place */
 199 static char *execname;
 200 static char target_brand[MAXNAMELEN];
 201 static char *locale;
 202 char *target_zone;
 203 static char *target_uuid;
 204 
 205 /* used in do_subproc() and signal handler */
 206 static volatile boolean_t child_killed;
 207 static int do_subproc_cnt = 0;
 208 
 209 /*
 210  * Used to indicate whether this zoneadm instance has another zoneadm
 211  * instance in its ancestry.
 212  */
 213 static boolean_t zoneadm_is_nested = B_FALSE;
 214 
 215 char *
 216 cmd_to_str(int cmd_num)
 217 {
 218         assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
 219         return (cmdtab[cmd_num].cmd_name);
 220 }
 221 
 222 /* This is a separate function because of gettext() wrapping. */
 223 static char *
 224 long_help(int cmd_num)
 225 {
 226         assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
 227         switch (cmd_num) {
 228         case CMD_HELP:
 229                 return (gettext("Print usage message."));
 230         case CMD_BOOT:
 231                 return (gettext("Activates (boots) specified zone.  See "
 232                     "zoneadm(1m) for valid boot\n\targuments."));
 233         case CMD_HALT:
 234                 return (gettext("Halts specified zone, bypassing shutdown "
 235                     "scripts and removing runtime\n\tresources of the zone."));
 236         case CMD_READY:
 237                 return (gettext("Prepares a zone for running applications but "
 238                     "does not start any user\n\tprocesses in the zone."));
 239         case CMD_REBOOT:
 240                 return (gettext("Restarts the zone (equivalent to a halt / "
 241                     "boot sequence).\n\tFails if the zone is not active.  "
 242                     "See zoneadm(1m) for valid boot\n\targuments."));
 243         case CMD_LIST:
 244                 return (gettext("Lists the current zones, or a "
 245                     "specific zone if indicated.  By default,\n\tall "
 246                     "running zones are listed, though this can be "
 247                     "expanded to all\n\tinstalled zones with the -i "
 248                     "option or all configured zones with the\n\t-c "
 249                     "option.  When used with the general -z <zone> and/or -u "
 250                     "<uuid-match>\n\toptions, lists only the specified "
 251                     "matching zone, but lists it\n\tregardless of its state, "
 252                     "and the -i and -c options are disallowed.  The\n\t-v "
 253                     "option can be used to display verbose information: zone "
 254                     "name, id,\n\tcurrent state, root directory and options.  "
 255                     "The -p option can be used\n\tto request machine-parsable "
 256                     "output.  The -v and -p options are mutually\n\texclusive."
 257                     "  If neither -v nor -p is used, just the zone name is "
 258                     "listed."));
 259         case CMD_VERIFY:
 260                 return (gettext("Check to make sure the configuration "
 261                     "can safely be instantiated\n\ton the machine: "
 262                     "physical network interfaces exist, etc."));
 263         case CMD_INSTALL:
 264                 return (gettext("Install the configuration on to the system.  "
 265                     "The -x nodataset option\n\tcan be used to prevent the "
 266                     "creation of a new ZFS file system for the\n\tzone "
 267                     "(assuming the zonepath is within a ZFS file system).\n\t"
 268                     "All other arguments are passed to the brand installation "
 269                     "function;\n\tsee brands(5) for more information."));
 270         case CMD_UNINSTALL:
 271                 return (gettext("Uninstall the configuration from the system.  "
 272                     "The -F flag can be used\n\tto force the action.  All "
 273                     "other arguments are passed to the brand\n\tuninstall "
 274                     "function; see brands(5) for more information."));
 275         case CMD_CLONE:
 276                 return (gettext("Clone the installation of another zone.  "
 277                     "The -m option can be used to\n\tspecify 'copy' which "
 278                     "forces a copy of the source zone.  The -s option\n\t"
 279                     "can be used to specify the name of a ZFS snapshot "
 280                     "that was taken from\n\ta previous clone command.  The "
 281                     "snapshot will be used as the source\n\tinstead of "
 282                     "creating a new ZFS snapshot.  All other arguments are "
 283                     "passed\n\tto the brand clone function; see "
 284                     "brands(5) for more information."));
 285         case CMD_MOVE:
 286                 return (gettext("Move the zone to a new zonepath."));
 287         case CMD_DETACH:
 288                 return (gettext("Detach the zone from the system. The zone "
 289                     "state is changed to\n\t'configured' (but the files under "
 290                     "the zonepath are untouched).\n\tThe zone can subsequently "
 291                     "be attached, or can be moved to another\n\tsystem and "
 292                     "attached there.  The -n option can be used to specify\n\t"
 293                     "'no-execute' mode.  When -n is used, the information "
 294                     "needed to attach\n\tthe zone is sent to standard output "
 295                     "but the zone is not actually\n\tdetached.  All other "
 296                     "arguments are passed to the brand detach function;\n\tsee "
 297                     "brands(5) for more information."));
 298         case CMD_ATTACH:
 299                 return (gettext("Attach the zone to the system.  The zone "
 300                     "state must be 'configured'\n\tprior to attach; upon "
 301                     "successful completion, the zone state will be\n\t"
 302                     "'installed'.  The system software on the current "
 303                     "system must be\n\tcompatible with the software on the "
 304                     "zone's original system.\n\tSpecify -F "
 305                     "to force the attach and skip software compatibility "
 306                     "tests.\n\tThe -n option can be used to specify "
 307                     "'no-execute' mode.  When -n is\n\tused, the information "
 308                     "needed to attach the zone is read from the\n\tspecified "
 309                     "path and the configuration is only validated.  The path "
 310                     "can\n\tbe '-' to specify standard input.  The -F and -n "
 311                     "options are mutually\n\texclusive.  All other arguments "
 312                     "are passed to the brand attach\n\tfunction; see "
 313                     "brands(5) for more information."));
 314         case CMD_MARK:
 315                 return (gettext("Set the state of the zone.  This can be used "
 316                     "to force the zone\n\tstate to 'incomplete' "
 317                     "administratively if some activity has rendered\n\tthe "
 318                     "zone permanently unusable.  The only valid state that "
 319                     "may be\n\tspecified is 'incomplete'."));
 320         default:
 321                 return ("");
 322         }
 323         /* NOTREACHED */
 324         return (NULL);
 325 }
 326 
 327 /*
 328  * Called with explicit B_TRUE when help is explicitly requested, B_FALSE for
 329  * unexpected errors.
 330  */
 331 
 332 static int
 333 usage(boolean_t explicit)
 334 {
 335         int i;
 336         FILE *fd = explicit ? stdout : stderr;
 337 
 338         (void) fprintf(fd, "%s:\t%s help\n", gettext("usage"), execname);
 339         (void) fprintf(fd, "\t%s [-z <zone>] [-u <uuid-match>] list\n",
 340             execname);
 341         (void) fprintf(fd, "\t%s {-z <zone>|-u <uuid-match>} <%s>\n", execname,
 342             gettext("subcommand"));
 343         (void) fprintf(fd, "\n%s:\n\n", gettext("Subcommands"));
 344         for (i = CMD_MIN; i <= CMD_MAX; i++) {
 345                 if (cmdtab[i].short_usage == NULL)
 346                         continue;
 347                 (void) fprintf(fd, "%s\n", cmdtab[i].short_usage);
 348                 if (explicit)
 349                         (void) fprintf(fd, "\t%s\n\n", long_help(i));
 350         }
 351         if (!explicit)
 352                 (void) fputs("\n", fd);
 353         return (Z_USAGE);
 354 }
 355 
 356 static void
 357 sub_usage(char *short_usage, int cmd_num)
 358 {
 359         (void) fprintf(stderr, "%s:\t%s\n", gettext("usage"), short_usage);
 360         (void) fprintf(stderr, "\t%s\n", long_help(cmd_num));
 361 }
 362 
 363 /*
 364  * zperror() is like perror(3c) except that this also prints the executable
 365  * name at the start of the message, and takes a boolean indicating whether
 366  * to call libc'c strerror() or that from libzonecfg.
 367  */
 368 
 369 void
 370 zperror(const char *str, boolean_t zonecfg_error)
 371 {
 372         (void) fprintf(stderr, "%s: %s: %s\n", execname, str,
 373             zonecfg_error ? zonecfg_strerror(errno) : strerror(errno));
 374 }
 375 
 376 /*
 377  * zperror2() is very similar to zperror() above, except it also prints a
 378  * supplied zone name after the executable.
 379  *
 380  * All current consumers of this function want libzonecfg's strerror() rather
 381  * than libc's; if this ever changes, this function can be made more generic
 382  * like zperror() above.
 383  */
 384 
 385 void
 386 zperror2(const char *zone, const char *str)
 387 {
 388         (void) fprintf(stderr, "%s: %s: %s: %s\n", execname, zone, str,
 389             zonecfg_strerror(errno));
 390 }
 391 
 392 /* PRINTFLIKE1 */
 393 void
 394 zerror(const char *fmt, ...)
 395 {
 396         va_list alist;
 397 
 398         va_start(alist, fmt);
 399         (void) fprintf(stderr, "%s: ", execname);
 400         if (target_zone != NULL)
 401                 (void) fprintf(stderr, "zone '%s': ", target_zone);
 402         (void) vfprintf(stderr, fmt, alist);
 403         (void) fprintf(stderr, "\n");
 404         va_end(alist);
 405 }
 406 
 407 static void *
 408 safe_calloc(size_t nelem, size_t elsize)
 409 {
 410         void *r = calloc(nelem, elsize);
 411 
 412         if (r == NULL) {
 413                 zerror(gettext("failed to allocate %lu bytes: %s"),
 414                     (ulong_t)nelem * elsize, strerror(errno));
 415                 exit(Z_ERR);
 416         }
 417         return (r);
 418 }
 419 
 420 static void
 421 zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
 422 {
 423         static boolean_t firsttime = B_TRUE;
 424         char *ip_type_str;
 425 
 426         if (zent->ziptype == ZS_EXCLUSIVE)
 427                 ip_type_str = "excl";
 428         else
 429                 ip_type_str = "shared";
 430 
 431         assert(!(verbose && parsable));
 432         if (firsttime && verbose) {
 433                 firsttime = B_FALSE;
 434                 (void) printf("%*s %-16s %-10s %-30s %-8s %-6s\n",
 435                     ZONEID_WIDTH, "ID", "NAME", "STATUS", "PATH", "BRAND",
 436                     "IP");
 437         }
 438         if (!verbose) {
 439                 char *cp, *clim;
 440 
 441                 if (!parsable) {
 442                         (void) printf("%s\n", zent->zname);
 443                         return;
 444                 }
 445                 if (zent->zid == ZONE_ID_UNDEFINED)
 446                         (void) printf("-");
 447                 else
 448                         (void) printf("%lu", zent->zid);
 449                 (void) printf(":%s:%s:", zent->zname, zent->zstate_str);
 450                 cp = zent->zroot;
 451                 while ((clim = strchr(cp, ':')) != NULL) {
 452                         (void) printf("%.*s\\:", clim - cp, cp);
 453                         cp = clim + 1;
 454                 }
 455                 (void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
 456                     ip_type_str);
 457                 return;
 458         }
 459         if (zent->zstate_str != NULL) {
 460                 if (zent->zid == ZONE_ID_UNDEFINED)
 461                         (void) printf("%*s", ZONEID_WIDTH, "-");
 462                 else
 463                         (void) printf("%*lu", ZONEID_WIDTH, zent->zid);
 464                 (void) printf(" %-16s %-10s %-30s %-8s %-6s\n", zent->zname,
 465                     zent->zstate_str, zent->zroot, zent->zbrand, ip_type_str);
 466         }
 467 }
 468 
 469 static int
 470 lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent)
 471 {
 472         char root[MAXPATHLEN], *cp;
 473         int err;
 474         uuid_t uuid;
 475 
 476         (void) strlcpy(zent->zname, zone_name, sizeof (zent->zname));
 477         (void) strlcpy(zent->zroot, "???", sizeof (zent->zroot));
 478         (void) strlcpy(zent->zbrand, "???", sizeof (zent->zbrand));
 479         zent->zstate_str = "???";
 480 
 481         zent->zid = zid;
 482 
 483         if (zonecfg_get_uuid(zone_name, uuid) == Z_OK &&
 484             !uuid_is_null(uuid))
 485                 uuid_unparse(uuid, zent->zuuid);
 486         else
 487                 zent->zuuid[0] = '\0';
 488 
 489         /*
 490          * For labeled zones which query the zone path of lower-level
 491          * zones, the path needs to be adjusted to drop the final
 492          * "/root" component. This adjusted path is then useful
 493          * for reading down any exported directories from the
 494          * lower-level zone.
 495          */
 496         if (is_system_labeled() && zent->zid != ZONE_ID_UNDEFINED) {
 497                 if (zone_getattr(zent->zid, ZONE_ATTR_ROOT, zent->zroot,
 498                     sizeof (zent->zroot)) == -1) {
 499                         zperror2(zent->zname,
 500                             gettext("could not get zone path."));
 501                         return (Z_ERR);
 502                 }
 503                 cp = zent->zroot + strlen(zent->zroot) - 5;
 504                 if (cp > zent->zroot && strcmp(cp, "/root") == 0)
 505                         *cp = 0;
 506         } else {
 507                 if ((err = zone_get_zonepath(zent->zname, root,
 508                     sizeof (root))) != Z_OK) {
 509                         errno = err;
 510                         zperror2(zent->zname,
 511                             gettext("could not get zone path."));
 512                         return (Z_ERR);
 513                 }
 514                 (void) strlcpy(zent->zroot, root, sizeof (zent->zroot));
 515         }
 516 
 517         if ((err = zone_get_state(zent->zname, &zent->zstate_num)) != Z_OK) {
 518                 errno = err;
 519                 zperror2(zent->zname, gettext("could not get state"));
 520                 return (Z_ERR);
 521         }
 522         zent->zstate_str = zone_state_str(zent->zstate_num);
 523 
 524         /*
 525          * A zone's brand is only available in the .xml file describing it,
 526          * which is only visible to the global zone.  This causes
 527          * zone_get_brand() to fail when called from within a non-global
 528          * zone.  Fortunately we only do this on labeled systems, where we
 529          * know all zones are native.
 530          */
 531         if (getzoneid() != GLOBAL_ZONEID) {
 532                 assert(is_system_labeled() != 0);
 533                 (void) strlcpy(zent->zbrand, NATIVE_BRAND_NAME,
 534                     sizeof (zent->zbrand));
 535         } else if (zone_get_brand(zent->zname, zent->zbrand,
 536             sizeof (zent->zbrand)) != Z_OK) {
 537                 zperror2(zent->zname, gettext("could not get brand name"));
 538                 return (Z_ERR);
 539         }
 540 
 541         /*
 542          * Get ip type of the zone.
 543          * Note for global zone, ZS_SHARED is set always.
 544          */
 545         if (zid == GLOBAL_ZONEID) {
 546                 zent->ziptype = ZS_SHARED;
 547         } else {
 548 
 549                 if (zent->zstate_num == ZONE_STATE_RUNNING) {
 550                         ushort_t flags;
 551 
 552                         if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
 553                             sizeof (flags)) < 0) {
 554                                 zperror2(zent->zname,
 555                                     gettext("could not get zone flags"));
 556                                 return (Z_ERR);
 557                         }
 558                         if (flags & ZF_NET_EXCL)
 559                                 zent->ziptype = ZS_EXCLUSIVE;
 560                         else
 561                                 zent->ziptype = ZS_SHARED;
 562                 } else {
 563                         zone_dochandle_t handle;
 564 
 565                         if ((handle = zonecfg_init_handle()) == NULL) {
 566                                 zperror2(zent->zname,
 567                                     gettext("could not init handle"));
 568                                 return (Z_ERR);
 569                         }
 570                         if ((err = zonecfg_get_handle(zent->zname, handle))
 571                             != Z_OK) {
 572                                 zperror2(zent->zname,
 573                                     gettext("could not get handle"));
 574                                 zonecfg_fini_handle(handle);
 575                                 return (Z_ERR);
 576                         }
 577 
 578                         if ((err = zonecfg_get_iptype(handle, &zent->ziptype))
 579                             != Z_OK) {
 580                                 zperror2(zent->zname,
 581                                     gettext("could not get ip-type"));
 582                                 zonecfg_fini_handle(handle);
 583                                 return (Z_ERR);
 584                         }
 585                         zonecfg_fini_handle(handle);
 586                 }
 587         }
 588 
 589         return (Z_OK);
 590 }
 591 
 592 /*
 593  * fetch_zents() calls zone_list(2) to find out how many zones are running
 594  * (which is stored in the global nzents), then calls zone_list(2) again
 595  * to fetch the list of running zones (stored in the global zents).  This
 596  * function may be called multiple times, so if zents is already set, we
 597  * return immediately to save work.
 598  */
 599 
 600 static int
 601 fetch_zents(void)
 602 {
 603         zoneid_t *zids = NULL;
 604         uint_t nzents_saved;
 605         int i, retv;
 606         FILE *fp;
 607         boolean_t inaltroot;
 608         zone_entry_t *zentp;
 609 
 610         if (nzents > 0)
 611                 return (Z_OK);
 612 
 613         if (zone_list(NULL, &nzents) != 0) {
 614                 zperror(gettext("failed to get zoneid list"), B_FALSE);
 615                 return (Z_ERR);
 616         }
 617 
 618 again:
 619         if (nzents == 0)
 620                 return (Z_OK);
 621 
 622         zids = safe_calloc(nzents, sizeof (zoneid_t));
 623         nzents_saved = nzents;
 624 
 625         if (zone_list(zids, &nzents) != 0) {
 626                 zperror(gettext("failed to get zone list"), B_FALSE);
 627                 free(zids);
 628                 return (Z_ERR);
 629         }
 630         if (nzents != nzents_saved) {
 631                 /* list changed, try again */
 632                 free(zids);
 633                 goto again;
 634         }
 635 
 636         zents = safe_calloc(nzents, sizeof (zone_entry_t));
 637 
 638         inaltroot = zonecfg_in_alt_root();
 639         if (inaltroot)
 640                 fp = zonecfg_open_scratch("", B_FALSE);
 641         else
 642                 fp = NULL;
 643         zentp = zents;
 644         retv = Z_OK;
 645         for (i = 0; i < nzents; i++) {
 646                 char name[ZONENAME_MAX];
 647                 char altname[ZONENAME_MAX];
 648 
 649                 if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) {
 650                         zperror(gettext("failed to get zone name"), B_FALSE);
 651                         retv = Z_ERR;
 652                         continue;
 653                 }
 654                 if (zonecfg_is_scratch(name)) {
 655                         /* Ignore scratch zones by default */
 656                         if (!inaltroot)
 657                                 continue;
 658                         if (fp == NULL ||
 659                             zonecfg_reverse_scratch(fp, name, altname,
 660                             sizeof (altname), NULL, 0) == -1) {
 661                                 zerror(gettext("could not resolve scratch "
 662                                     "zone %s"), name);
 663                                 retv = Z_ERR;
 664                                 continue;
 665                         }
 666                         (void) strcpy(name, altname);
 667                 } else {
 668                         /* Ignore non-scratch when in an alternate root */
 669                         if (inaltroot && strcmp(name, GLOBAL_ZONENAME) != 0)
 670                                 continue;
 671                 }
 672                 if (lookup_zone_info(name, zids[i], zentp) != Z_OK) {
 673                         zerror(gettext("failed to get zone data"));
 674                         retv = Z_ERR;
 675                         continue;
 676                 }
 677                 zentp++;
 678         }
 679         nzents = zentp - zents;
 680         if (fp != NULL)
 681                 zonecfg_close_scratch(fp);
 682 
 683         free(zids);
 684         return (retv);
 685 }
 686 
 687 static int
 688 zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable)
 689 {
 690         int i;
 691         zone_entry_t zent;
 692         FILE *cookie;
 693         char *name;
 694 
 695         /*
 696          * First get the list of running zones from the kernel and print them.
 697          * If that is all we need, then return.
 698          */
 699         if ((i = fetch_zents()) != Z_OK) {
 700                 /*
 701                  * No need for error messages; fetch_zents() has already taken
 702                  * care of this.
 703                  */
 704                 return (i);
 705         }
 706         for (i = 0; i < nzents; i++)
 707                 zone_print(&zents[i], verbose, parsable);
 708         if (min_state >= ZONE_STATE_RUNNING)
 709                 return (Z_OK);
 710         /*
 711          * Next, get the full list of zones from the configuration, skipping
 712          * any we have already printed.
 713          */
 714         cookie = setzoneent();
 715         while ((name = getzoneent(cookie)) != NULL) {
 716                 for (i = 0; i < nzents; i++) {
 717                         if (strcmp(zents[i].zname, name) == 0)
 718                                 break;
 719                 }
 720                 if (i < nzents) {
 721                         free(name);
 722                         continue;
 723                 }
 724                 if (lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
 725                         free(name);
 726                         continue;
 727                 }
 728                 free(name);
 729                 if (zent.zstate_num >= min_state)
 730                         zone_print(&zent, verbose, parsable);
 731         }
 732         endzoneent(cookie);
 733         return (Z_OK);
 734 }
 735 
 736 /*
 737  * Retrieve a zone entry by name.  Returns NULL if no such zone exists.
 738  */
 739 static zone_entry_t *
 740 lookup_running_zone(const char *str)
 741 {
 742         int i;
 743 
 744         if (fetch_zents() != Z_OK)
 745                 return (NULL);
 746 
 747         for (i = 0; i < nzents; i++) {
 748                 if (strcmp(str, zents[i].zname) == 0)
 749                         return (&zents[i]);
 750         }
 751         return (NULL);
 752 }
 753 
 754 /*
 755  * Check a bit in a mode_t: if on is B_TRUE, that bit should be on; if
 756  * B_FALSE, it should be off.  Return B_TRUE if the mode is bad (incorrect).
 757  */
 758 static boolean_t
 759 bad_mode_bit(mode_t mode, mode_t bit, boolean_t on, char *file)
 760 {
 761         char *str;
 762 
 763         assert(bit == S_IRUSR || bit == S_IWUSR || bit == S_IXUSR ||
 764             bit == S_IRGRP || bit == S_IWGRP || bit == S_IXGRP ||
 765             bit == S_IROTH || bit == S_IWOTH || bit == S_IXOTH);
 766         /*
 767          * TRANSLATION_NOTE
 768          * The strings below will be used as part of a larger message,
 769          * either:
 770          * (file name) must be (owner|group|world) (read|writ|execut)able
 771          * or
 772          * (file name) must not be (owner|group|world) (read|writ|execut)able
 773          */
 774         switch (bit) {
 775         case S_IRUSR:
 776                 str = gettext("owner readable");
 777                 break;
 778         case S_IWUSR:
 779                 str = gettext("owner writable");
 780                 break;
 781         case S_IXUSR:
 782                 str = gettext("owner executable");
 783                 break;
 784         case S_IRGRP:
 785                 str = gettext("group readable");
 786                 break;
 787         case S_IWGRP:
 788                 str = gettext("group writable");
 789                 break;
 790         case S_IXGRP:
 791                 str = gettext("group executable");
 792                 break;
 793         case S_IROTH:
 794                 str = gettext("world readable");
 795                 break;
 796         case S_IWOTH:
 797                 str = gettext("world writable");
 798                 break;
 799         case S_IXOTH:
 800                 str = gettext("world executable");
 801                 break;
 802         }
 803         if ((mode & bit) == (on ? 0 : bit)) {
 804                 /*
 805                  * TRANSLATION_NOTE
 806                  * The first parameter below is a file name; the second
 807                  * is one of the "(owner|group|world) (read|writ|execut)able"
 808                  * strings from above.
 809                  */
 810                 /*
 811                  * The code below could be simplified but not in a way
 812                  * that would easily translate to non-English locales.
 813                  */
 814                 if (on) {
 815                         (void) fprintf(stderr, gettext("%s must be %s.\n"),
 816                             file, str);
 817                 } else {
 818                         (void) fprintf(stderr, gettext("%s must not be %s.\n"),
 819                             file, str);
 820                 }
 821                 return (B_TRUE);
 822         }
 823         return (B_FALSE);
 824 }
 825 
 826 /*
 827  * We want to make sure that no zone has its zone path as a child node
 828  * (in the directory sense) of any other.  We do that by comparing this
 829  * zone's path to the path of all other (non-global) zones.  The comparison
 830  * in each case is simple: add '/' to the end of the path, then do a
 831  * strncmp() of the two paths, using the length of the shorter one.
 832  */
 833 
 834 static int
 835 crosscheck_zonepaths(char *path)
 836 {
 837         char rpath[MAXPATHLEN];         /* resolved path */
 838         char path_copy[MAXPATHLEN];     /* copy of original path */
 839         char rpath_copy[MAXPATHLEN];    /* copy of original rpath */
 840         struct zoneent *ze;
 841         int res, err;
 842         FILE *cookie;
 843 
 844         cookie = setzoneent();
 845         while ((ze = getzoneent_private(cookie)) != NULL) {
 846                 /* Skip zones which are not installed. */
 847                 if (ze->zone_state < ZONE_STATE_INSTALLED) {
 848                         free(ze);
 849                         continue;
 850                 }
 851                 /* Skip the global zone and the current target zone. */
 852                 if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0 ||
 853                     strcmp(ze->zone_name, target_zone) == 0) {
 854                         free(ze);
 855                         continue;
 856                 }
 857                 if (strlen(ze->zone_path) == 0) {
 858                         /* old index file without path, fall back */
 859                         if ((err = zone_get_zonepath(ze->zone_name,
 860                             ze->zone_path, sizeof (ze->zone_path))) != Z_OK) {
 861                                 errno = err;
 862                                 zperror2(ze->zone_name,
 863                                     gettext("could not get zone path"));
 864                                 free(ze);
 865                                 continue;
 866                         }
 867                 }
 868                 (void) snprintf(path_copy, sizeof (path_copy), "%s%s",
 869                     zonecfg_get_root(), ze->zone_path);
 870                 res = resolvepath(path_copy, rpath, sizeof (rpath));
 871                 if (res == -1) {
 872                         if (errno != ENOENT) {
 873                                 zperror(path_copy, B_FALSE);
 874                                 free(ze);
 875                                 return (Z_ERR);
 876                         }
 877                         (void) printf(gettext("WARNING: zone %s is installed, "
 878                             "but its %s %s does not exist.\n"), ze->zone_name,
 879                             "zonepath", path_copy);
 880                         free(ze);
 881                         continue;
 882                 }
 883                 rpath[res] = '\0';
 884                 (void) snprintf(path_copy, sizeof (path_copy), "%s/", path);
 885                 (void) snprintf(rpath_copy, sizeof (rpath_copy), "%s/", rpath);
 886                 if (strncmp(path_copy, rpath_copy,
 887                     min(strlen(path_copy), strlen(rpath_copy))) == 0) {
 888                         /*
 889                          * TRANSLATION_NOTE
 890                          * zonepath is a literal that should not be translated.
 891                          */
 892                         (void) fprintf(stderr, gettext("%s zonepath (%s) and "
 893                             "%s zonepath (%s) overlap.\n"),
 894                             target_zone, path, ze->zone_name, rpath);
 895                         free(ze);
 896                         return (Z_ERR);
 897                 }
 898                 free(ze);
 899         }
 900         endzoneent(cookie);
 901         return (Z_OK);
 902 }
 903 
 904 static int
 905 validate_zonepath(char *path, int cmd_num)
 906 {
 907         int res;                        /* result of last library/system call */
 908         boolean_t err = B_FALSE;        /* have we run into an error? */
 909         struct stat stbuf;
 910         struct statvfs64 vfsbuf;
 911         char rpath[MAXPATHLEN];         /* resolved path */
 912         char ppath[MAXPATHLEN];         /* parent path */
 913         char rppath[MAXPATHLEN];        /* resolved parent path */
 914         char rootpath[MAXPATHLEN];      /* root path */
 915         zone_state_t state;
 916 
 917         if (path[0] != '/') {
 918                 (void) fprintf(stderr,
 919                     gettext("%s is not an absolute path.\n"), path);
 920                 return (Z_ERR);
 921         }
 922         if ((res = resolvepath(path, rpath, sizeof (rpath))) == -1) {
 923                 if ((errno != ENOENT) ||
 924                     (cmd_num != CMD_VERIFY && cmd_num != CMD_INSTALL &&
 925                     cmd_num != CMD_CLONE && cmd_num != CMD_MOVE)) {
 926                         zperror(path, B_FALSE);
 927                         return (Z_ERR);
 928                 }
 929                 if (cmd_num == CMD_VERIFY) {
 930                         /*
 931                          * TRANSLATION_NOTE
 932                          * zoneadm is a literal that should not be translated.
 933                          */
 934                         (void) fprintf(stderr, gettext("WARNING: %s does not "
 935                             "exist, so it could not be verified.\nWhen "
 936                             "'zoneadm %s' is run, '%s' will try to create\n%s, "
 937                             "and '%s' will be tried again,\nbut the '%s' may "
 938                             "fail if:\nthe parent directory of %s is group- or "
 939                             "other-writable\nor\n%s overlaps with any other "
 940                             "installed zones.\n"), path,
 941                             cmd_to_str(CMD_INSTALL), cmd_to_str(CMD_INSTALL),
 942                             path, cmd_to_str(CMD_VERIFY),
 943                             cmd_to_str(CMD_VERIFY), path, path);
 944                         return (Z_OK);
 945                 }
 946                 /*
 947                  * The zonepath is supposed to be mode 700 but its
 948                  * parent(s) 755.  So use 755 on the mkdirp() then
 949                  * chmod() the zonepath itself to 700.
 950                  */
 951                 if (mkdirp(path, DEFAULT_DIR_MODE) < 0) {
 952                         zperror(path, B_FALSE);
 953                         return (Z_ERR);
 954                 }
 955                 /*
 956                  * If the chmod() fails, report the error, but might
 957                  * as well continue the verify procedure.
 958                  */
 959                 if (chmod(path, S_IRWXU) != 0)
 960                         zperror(path, B_FALSE);
 961                 /*
 962                  * Since the mkdir() succeeded, we should not have to
 963                  * worry about a subsequent ENOENT, thus this should
 964                  * only recurse once.
 965                  */
 966                 return (validate_zonepath(path, cmd_num));
 967         }
 968         rpath[res] = '\0';
 969         if (strcmp(path, rpath) != 0) {
 970                 errno = Z_RESOLVED_PATH;
 971                 zperror(path, B_TRUE);
 972                 return (Z_ERR);
 973         }
 974         if ((res = stat(rpath, &stbuf)) != 0) {
 975                 zperror(rpath, B_FALSE);
 976                 return (Z_ERR);
 977         }
 978         if (!S_ISDIR(stbuf.st_mode)) {
 979                 (void) fprintf(stderr, gettext("%s is not a directory.\n"),
 980                     rpath);
 981                 return (Z_ERR);
 982         }
 983         if (strcmp(stbuf.st_fstype, MNTTYPE_TMPFS) == 0) {
 984                 (void) printf(gettext("WARNING: %s is on a temporary "
 985                     "file system.\n"), rpath);
 986         }
 987         if (crosscheck_zonepaths(rpath) != Z_OK)
 988                 return (Z_ERR);
 989         /*
 990          * Try to collect and report as many minor errors as possible
 991          * before returning, so the user can learn everything that needs
 992          * to be fixed up front.
 993          */
 994         if (stbuf.st_uid != 0) {
 995                 (void) fprintf(stderr, gettext("%s is not owned by root.\n"),
 996                     rpath);
 997                 err = B_TRUE;
 998         }
 999         err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rpath);
1000         err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rpath);
1001         err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rpath);
1002         err |= bad_mode_bit(stbuf.st_mode, S_IRGRP, B_FALSE, rpath);
1003         err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rpath);
1004         err |= bad_mode_bit(stbuf.st_mode, S_IXGRP, B_FALSE, rpath);
1005         err |= bad_mode_bit(stbuf.st_mode, S_IROTH, B_FALSE, rpath);
1006         err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rpath);
1007         err |= bad_mode_bit(stbuf.st_mode, S_IXOTH, B_FALSE, rpath);
1008 
1009         (void) snprintf(ppath, sizeof (ppath), "%s/..", path);
1010         if ((res = resolvepath(ppath, rppath, sizeof (rppath))) == -1) {
1011                 zperror(ppath, B_FALSE);
1012                 return (Z_ERR);
1013         }
1014         rppath[res] = '\0';
1015         if ((res = stat(rppath, &stbuf)) != 0) {
1016                 zperror(rppath, B_FALSE);
1017                 return (Z_ERR);
1018         }
1019         /* theoretically impossible */
1020         if (!S_ISDIR(stbuf.st_mode)) {
1021                 (void) fprintf(stderr, gettext("%s is not a directory.\n"),
1022                     rppath);
1023                 return (Z_ERR);
1024         }
1025         if (stbuf.st_uid != 0) {
1026                 (void) fprintf(stderr, gettext("%s is not owned by root.\n"),
1027                     rppath);
1028                 err = B_TRUE;
1029         }
1030         err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rppath);
1031         err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rppath);
1032         err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rppath);
1033         err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rppath);
1034         err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rppath);
1035         if (strcmp(rpath, rppath) == 0) {
1036                 (void) fprintf(stderr, gettext("%s is its own parent.\n"),
1037                     rppath);
1038                 err = B_TRUE;
1039         }
1040 
1041         if (statvfs64(rpath, &vfsbuf) != 0) {
1042                 zperror(rpath, B_FALSE);
1043                 return (Z_ERR);
1044         }
1045         if (strcmp(vfsbuf.f_basetype, MNTTYPE_NFS) == 0) {
1046                 /*
1047                  * TRANSLATION_NOTE
1048                  * Zonepath and NFS are literals that should not be translated.
1049                  */
1050                 (void) fprintf(stderr, gettext("Zonepath %s is on an NFS "
1051                     "mounted file system.\n"
1052                     "\tA local file system must be used.\n"), rpath);
1053                 return (Z_ERR);
1054         }
1055         if (vfsbuf.f_flag & ST_NOSUID) {
1056                 /*
1057                  * TRANSLATION_NOTE
1058                  * Zonepath and nosuid are literals that should not be
1059                  * translated.
1060                  */
1061                 (void) fprintf(stderr, gettext("Zonepath %s is on a nosuid "
1062                     "file system.\n"), rpath);
1063                 return (Z_ERR);
1064         }
1065 
1066         if ((res = zone_get_state(target_zone, &state)) != Z_OK) {
1067                 errno = res;
1068                 zperror2(target_zone, gettext("could not get state"));
1069                 return (Z_ERR);
1070         }
1071         /*
1072          * The existence of the root path is only bad in the configured state,
1073          * as it is *supposed* to be there at the installed and later states.
1074          * However, the root path is expected to be there if the zone is
1075          * detached.
1076          * State/command mismatches are caught earlier in verify_details().
1077          */
1078         if (state == ZONE_STATE_CONFIGURED && cmd_num != CMD_ATTACH) {
1079                 if (snprintf(rootpath, sizeof (rootpath), "%s/root", rpath) >=
1080                     sizeof (rootpath)) {
1081                         /*
1082                          * TRANSLATION_NOTE
1083                          * Zonepath is a literal that should not be translated.
1084                          */
1085                         (void) fprintf(stderr,
1086                             gettext("Zonepath %s is too long.\n"), rpath);
1087                         return (Z_ERR);
1088                 }
1089                 if ((res = stat(rootpath, &stbuf)) == 0) {
1090                         struct dirent   *dp;
1091                         DIR             *dirp;
1092                         boolean_t       empty = B_TRUE;
1093 
1094                         if (zonecfg_detached(rpath)) {
1095                                 (void) fprintf(stderr,
1096                                     gettext("Cannot %s detached "
1097                                     "zone.\nUse attach or remove %s "
1098                                     "directory.\n"), cmd_to_str(cmd_num),
1099                                     rpath);
1100                                 return (Z_ERR);
1101                         }
1102 
1103                         /* Not detached, check if it really looks ok. */
1104 
1105                         if (!S_ISDIR(stbuf.st_mode)) {
1106                                 (void) fprintf(stderr, gettext("%s is not a "
1107                                     "directory.\n"), rootpath);
1108                                 return (Z_ERR);
1109                         }
1110 
1111                         if (stbuf.st_uid != 0) {
1112                                 (void) fprintf(stderr, gettext("%s is not "
1113                                     "owned by root.\n"), rootpath);
1114                                 return (Z_ERR);
1115                         }
1116 
1117                         if ((stbuf.st_mode & 0777) != 0755) {
1118                                 (void) fprintf(stderr, gettext("%s mode is not "
1119                                     "0755.\n"), rootpath);
1120                                 return (Z_ERR);
1121                         }
1122 
1123                         if ((dirp = opendir(rootpath)) == NULL) {
1124                                 (void) fprintf(stderr, gettext("Could not "
1125                                     "open rootpath %s\n"), rootpath);
1126                                 return (Z_ERR);
1127                         }
1128 
1129                         /* Verify that the dir is empty. */
1130                         while ((dp = readdir(dirp)) != NULL) {
1131                                 if (strcmp(dp->d_name, ".") == 0 ||
1132                                     strcmp(dp->d_name, "..") == 0)
1133                                         continue;
1134 
1135                                 empty = B_FALSE;
1136                                 break;
1137                         }
1138                         (void) closedir(dirp);
1139 
1140                         if (!empty) {
1141                                 (void) fprintf(stderr, gettext("Rootpath %s "
1142                                     "exists and contains data; remove or move "
1143                                     "aside prior to %s.\n"), rootpath,
1144                                     cmd_to_str(cmd_num));
1145                                 return (Z_ERR);
1146                         }
1147 
1148                 }
1149         }
1150 
1151         return (err ? Z_ERR : Z_OK);
1152 }
1153 
1154 static int
1155 invoke_brand_handler(int cmd_num, char *argv[])
1156 {
1157         zone_dochandle_t handle;
1158         int err;
1159 
1160         if ((handle = zonecfg_init_handle()) == NULL) {
1161                 zperror(cmd_to_str(cmd_num), B_TRUE);
1162                 return (Z_ERR);
1163         }
1164         if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
1165                 errno = err;
1166                 zperror(cmd_to_str(cmd_num), B_TRUE);
1167                 zonecfg_fini_handle(handle);
1168                 return (Z_ERR);
1169         }
1170         if (verify_brand(handle, cmd_num, argv) != Z_OK) {
1171                 zonecfg_fini_handle(handle);
1172                 return (Z_ERR);
1173         }
1174         zonecfg_fini_handle(handle);
1175         return (Z_OK);
1176 }
1177 
1178 static int
1179 ready_func(int argc, char *argv[])
1180 {
1181         zone_cmd_arg_t zarg;
1182         int arg;
1183 
1184         if (zonecfg_in_alt_root()) {
1185                 zerror(gettext("cannot ready zone in alternate root"));
1186                 return (Z_ERR);
1187         }
1188 
1189         optind = 0;
1190         if ((arg = getopt(argc, argv, "?")) != EOF) {
1191                 switch (arg) {
1192                 case '?':
1193                         sub_usage(SHELP_READY, CMD_READY);
1194                         return (optopt == '?' ? Z_OK : Z_USAGE);
1195                 default:
1196                         sub_usage(SHELP_READY, CMD_READY);
1197                         return (Z_USAGE);
1198                 }
1199         }
1200         if (argc > optind) {
1201                 sub_usage(SHELP_READY, CMD_READY);
1202                 return (Z_USAGE);
1203         }
1204         if (sanity_check(target_zone, CMD_READY, B_FALSE, B_FALSE, B_FALSE)
1205             != Z_OK)
1206                 return (Z_ERR);
1207         if (verify_details(CMD_READY, argv) != Z_OK)
1208                 return (Z_ERR);
1209 
1210         zarg.cmd = Z_READY;
1211         if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
1212                 zerror(gettext("call to %s failed"), "zoneadmd");
1213                 return (Z_ERR);
1214         }
1215         return (Z_OK);
1216 }
1217 
1218 static int
1219 boot_func(int argc, char *argv[])
1220 {
1221         zone_cmd_arg_t zarg;
1222         boolean_t force = B_FALSE;
1223         int arg;
1224 
1225         if (zonecfg_in_alt_root()) {
1226                 zerror(gettext("cannot boot zone in alternate root"));
1227                 return (Z_ERR);
1228         }
1229 
1230         zarg.bootbuf[0] = '\0';
1231 
1232         /*
1233          * The following getopt processes arguments to zone boot; that
1234          * is to say, the [here] portion of the argument string:
1235          *
1236          *      zoneadm -z myzone boot [here] -- -v -m verbose
1237          *
1238          * Where [here] can either be nothing, -? (in which case we bail
1239          * and print usage), -f (a private option to indicate that the
1240          * boot operation should be 'forced'), or -s.  Support for -s is
1241          * vestigal and obsolete, but is retained because it was a
1242          * documented interface and there are known consumers including
1243          * admin/install; the proper way to specify boot arguments like -s
1244          * is:
1245          *
1246          *      zoneadm -z myzone boot -- -s -v -m verbose.
1247          */
1248         optind = 0;
1249         while ((arg = getopt(argc, argv, "?fs")) != EOF) {
1250                 switch (arg) {
1251                 case '?':
1252                         sub_usage(SHELP_BOOT, CMD_BOOT);
1253                         return (optopt == '?' ? Z_OK : Z_USAGE);
1254                 case 's':
1255                         (void) strlcpy(zarg.bootbuf, "-s",
1256                             sizeof (zarg.bootbuf));
1257                         break;
1258                 case 'f':
1259                         force = B_TRUE;
1260                         break;
1261                 default:
1262                         sub_usage(SHELP_BOOT, CMD_BOOT);
1263                         return (Z_USAGE);
1264                 }
1265         }
1266 
1267         for (; optind < argc; optind++) {
1268                 if (strlcat(zarg.bootbuf, argv[optind],
1269                     sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) {
1270                         zerror(gettext("Boot argument list too long"));
1271                         return (Z_ERR);
1272                 }
1273                 if (optind < argc - 1)
1274                         if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >=
1275                             sizeof (zarg.bootbuf)) {
1276                                 zerror(gettext("Boot argument list too long"));
1277                                 return (Z_ERR);
1278                         }
1279         }
1280         if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE, force)
1281             != Z_OK)
1282                 return (Z_ERR);
1283         if (verify_details(CMD_BOOT, argv) != Z_OK)
1284                 return (Z_ERR);
1285         zarg.cmd = force ? Z_FORCEBOOT : Z_BOOT;
1286         if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
1287                 zerror(gettext("call to %s failed"), "zoneadmd");
1288                 return (Z_ERR);
1289         }
1290 
1291         return (Z_OK);
1292 }
1293 
1294 static void
1295 fake_up_local_zone(zoneid_t zid, zone_entry_t *zeptr)
1296 {
1297         ssize_t result;
1298         uuid_t uuid;
1299         FILE *fp;
1300         ushort_t flags;
1301 
1302         (void) memset(zeptr, 0, sizeof (*zeptr));
1303 
1304         zeptr->zid = zid;
1305 
1306         /*
1307          * Since we're looking up our own (non-global) zone name,
1308          * we can be assured that it will succeed.
1309          */
1310         result = getzonenamebyid(zid, zeptr->zname, sizeof (zeptr->zname));
1311         assert(result >= 0);
1312         if (zonecfg_is_scratch(zeptr->zname) &&
1313             (fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
1314                 (void) zonecfg_reverse_scratch(fp, zeptr->zname, zeptr->zname,
1315                     sizeof (zeptr->zname), NULL, 0);
1316                 zonecfg_close_scratch(fp);
1317         }
1318 
1319         if (is_system_labeled()) {
1320                 (void) zone_getattr(zid, ZONE_ATTR_ROOT, zeptr->zroot,
1321                     sizeof (zeptr->zroot));
1322                 (void) strlcpy(zeptr->zbrand, NATIVE_BRAND_NAME,
1323                     sizeof (zeptr->zbrand));
1324         } else {
1325                 (void) strlcpy(zeptr->zroot, "/", sizeof (zeptr->zroot));
1326                 (void) zone_getattr(zid, ZONE_ATTR_BRAND, zeptr->zbrand,
1327                     sizeof (zeptr->zbrand));
1328         }
1329 
1330         zeptr->zstate_str = "running";
1331         if (zonecfg_get_uuid(zeptr->zname, uuid) == Z_OK &&
1332             !uuid_is_null(uuid))
1333                 uuid_unparse(uuid, zeptr->zuuid);
1334 
1335         if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags, sizeof (flags)) < 0) {
1336                 zperror2(zeptr->zname, gettext("could not get zone flags"));
1337                 exit(Z_ERR);
1338         }
1339         if (flags & ZF_NET_EXCL)
1340                 zeptr->ziptype = ZS_EXCLUSIVE;
1341         else
1342                 zeptr->ziptype = ZS_SHARED;
1343 }
1344 
1345 static int
1346 list_func(int argc, char *argv[])
1347 {
1348         zone_entry_t *zentp, zent;
1349         int arg, retv;
1350         boolean_t output = B_FALSE, verbose = B_FALSE, parsable = B_FALSE;
1351         zone_state_t min_state = ZONE_STATE_RUNNING;
1352         zoneid_t zone_id = getzoneid();
1353 
1354         if (target_zone == NULL) {
1355                 /* all zones: default view to running but allow override */
1356                 optind = 0;
1357                 while ((arg = getopt(argc, argv, "?cipv")) != EOF) {
1358                         switch (arg) {
1359                         case '?':
1360                                 sub_usage(SHELP_LIST, CMD_LIST);
1361                                 return (optopt == '?' ? Z_OK : Z_USAGE);
1362                                 /*
1363                                  * The 'i' and 'c' options are not mutually
1364                                  * exclusive so if 'c' is given, then min_state
1365                                  * is set to 0 (ZONE_STATE_CONFIGURED) which is
1366                                  * the lowest possible state.  If 'i' is given,
1367                                  * then min_state is set to be the lowest state
1368                                  * so far.
1369                                  */
1370                         case 'c':
1371                                 min_state = ZONE_STATE_CONFIGURED;
1372                                 break;
1373                         case 'i':
1374                                 min_state = min(ZONE_STATE_INSTALLED,
1375                                     min_state);
1376 
1377                                 break;
1378                         case 'p':
1379                                 parsable = B_TRUE;
1380                                 break;
1381                         case 'v':
1382                                 verbose = B_TRUE;
1383                                 break;
1384                         default:
1385                                 sub_usage(SHELP_LIST, CMD_LIST);
1386                                 return (Z_USAGE);
1387                         }
1388                 }
1389                 if (parsable && verbose) {
1390                         zerror(gettext("%s -p and -v are mutually exclusive."),
1391                             cmd_to_str(CMD_LIST));
1392                         return (Z_ERR);
1393                 }
1394                 if (zone_id == GLOBAL_ZONEID || is_system_labeled()) {
1395                         retv = zone_print_list(min_state, verbose, parsable);
1396                 } else {
1397                         fake_up_local_zone(zone_id, &zent);
1398                         retv = Z_OK;
1399                         zone_print(&zent, verbose, parsable);
1400                 }
1401                 return (retv);
1402         }
1403 
1404         /*
1405          * Specific target zone: disallow -i/-c suboptions.
1406          */
1407         optind = 0;
1408         while ((arg = getopt(argc, argv, "?pv")) != EOF) {
1409                 switch (arg) {
1410                 case '?':
1411                         sub_usage(SHELP_LIST, CMD_LIST);
1412                         return (optopt == '?' ? Z_OK : Z_USAGE);
1413                 case 'p':
1414                         parsable = B_TRUE;
1415                         break;
1416                 case 'v':
1417                         verbose = B_TRUE;
1418                         break;
1419                 default:
1420                         sub_usage(SHELP_LIST, CMD_LIST);
1421                         return (Z_USAGE);
1422                 }
1423         }
1424         if (parsable && verbose) {
1425                 zerror(gettext("%s -p and -v are mutually exclusive."),
1426                     cmd_to_str(CMD_LIST));
1427                 return (Z_ERR);
1428         }
1429         if (argc > optind) {
1430                 sub_usage(SHELP_LIST, CMD_LIST);
1431                 return (Z_USAGE);
1432         }
1433         if (zone_id != GLOBAL_ZONEID && !is_system_labeled()) {
1434                 fake_up_local_zone(zone_id, &zent);
1435                 /*
1436                  * main() will issue a Z_NO_ZONE error if it cannot get an
1437                  * id for target_zone, which in a non-global zone should
1438                  * happen for any zone name except `zonename`.  Thus we
1439                  * assert() that here but don't otherwise check.
1440                  */
1441                 assert(strcmp(zent.zname, target_zone) == 0);
1442                 zone_print(&zent, verbose, parsable);
1443                 output = B_TRUE;
1444         } else if ((zentp = lookup_running_zone(target_zone)) != NULL) {
1445                 zone_print(zentp, verbose, parsable);
1446                 output = B_TRUE;
1447         } else if (lookup_zone_info(target_zone, ZONE_ID_UNDEFINED,
1448             &zent) == Z_OK) {
1449                 zone_print(&zent, verbose, parsable);
1450                 output = B_TRUE;
1451         }
1452 
1453         /*
1454          * Invoke brand-specific handler. Note that we do this
1455          * only if we're in the global zone, and target_zone is specified
1456          * and it is not the global zone.
1457          */
1458         if (zone_id == GLOBAL_ZONEID && target_zone != NULL &&
1459             strcmp(target_zone, GLOBAL_ZONENAME) != 0)
1460                 if (invoke_brand_handler(CMD_LIST, argv) != Z_OK)
1461                         return (Z_ERR);
1462 
1463         return (output ? Z_OK : Z_ERR);
1464 }
1465 
1466 static void
1467 sigterm(int sig)
1468 {
1469         /*
1470          * Ignore SIG{INT,TERM}, so we don't end up in an infinite loop,
1471          * then propagate the signal to our process group.
1472          */
1473         assert(sig == SIGINT || sig == SIGTERM);
1474         (void) sigset(SIGINT, SIG_IGN);
1475         (void) sigset(SIGTERM, SIG_IGN);
1476         (void) kill(0, sig);
1477         child_killed = B_TRUE;
1478 }
1479 
1480 static int
1481 do_subproc(char *cmdbuf)
1482 {
1483         char inbuf[1024];       /* arbitrary large amount */
1484         FILE *file;
1485 
1486         do_subproc_cnt++;
1487         child_killed = B_FALSE;
1488         /*
1489          * We use popen(3c) to launch child processes for [un]install;
1490          * this library call does not return a PID, so we have to kill
1491          * the whole process group.  To avoid killing our parent, we
1492          * become a process group leader here.  But doing so can wreak
1493          * havoc with reading from stdin when launched by a non-job-control
1494          * shell, so we close stdin and reopen it as /dev/null first.
1495          */
1496         (void) close(STDIN_FILENO);
1497         (void) openat(STDIN_FILENO, "/dev/null", O_RDONLY);
1498         if (!zoneadm_is_nested)
1499                 (void) setpgid(0, 0);
1500         (void) sigset(SIGINT, sigterm);
1501         (void) sigset(SIGTERM, sigterm);
1502         file = popen(cmdbuf, "r");
1503         for (;;) {
1504                 if (child_killed || fgets(inbuf, sizeof (inbuf), file) == NULL)
1505                         break;
1506                 (void) fputs(inbuf, stdout);
1507         }
1508         (void) sigset(SIGINT, SIG_DFL);
1509         (void) sigset(SIGTERM, SIG_DFL);
1510         return (pclose(file));
1511 }
1512 
1513 int
1514 do_subproc_interactive(char *cmdbuf)
1515 {
1516         void (*saveint)(int);
1517         void (*saveterm)(int);
1518         void (*savequit)(int);
1519         void (*savehup)(int);
1520         int pid, child, status;
1521 
1522         /*
1523          * do_subproc() links stdin to /dev/null, which would break any
1524          * interactive subprocess we try to launch here.  Similarly, we
1525          * can't have been launched as a subprocess ourselves.
1526          */
1527         assert(do_subproc_cnt == 0 && !zoneadm_is_nested);
1528 
1529         if ((child = vfork()) == 0) {
1530                 (void) execl("/bin/sh", "sh", "-c", cmdbuf, (char *)NULL);
1531         }
1532 
1533         if (child == -1)
1534                 return (-1);
1535 
1536         saveint = sigset(SIGINT, SIG_IGN);
1537         saveterm = sigset(SIGTERM, SIG_IGN);
1538         savequit = sigset(SIGQUIT, SIG_IGN);
1539         savehup = sigset(SIGHUP, SIG_IGN);
1540 
1541         while ((pid = waitpid(child, &status, 0)) != child && pid != -1)
1542                 ;
1543 
1544         (void) sigset(SIGINT, saveint);
1545         (void) sigset(SIGTERM, saveterm);
1546         (void) sigset(SIGQUIT, savequit);
1547         (void) sigset(SIGHUP, savehup);
1548 
1549         return (pid == -1 ? -1 : status);
1550 }
1551 
1552 int
1553 subproc_status(const char *cmd, int status, boolean_t verbose_failure)
1554 {
1555         if (WIFEXITED(status)) {
1556                 int exit_code = WEXITSTATUS(status);
1557 
1558                 if ((verbose_failure) && (exit_code != ZONE_SUBPROC_OK))
1559                         zerror(gettext("'%s' failed with exit code %d."), cmd,
1560                             exit_code);
1561 
1562                 return (exit_code);
1563         } else if (WIFSIGNALED(status)) {
1564                 int signal = WTERMSIG(status);
1565                 char sigstr[SIG2STR_MAX];
1566 
1567                 if (sig2str(signal, sigstr) == 0) {
1568                         zerror(gettext("'%s' terminated by signal SIG%s."), cmd,
1569                             sigstr);
1570                 } else {
1571                         zerror(gettext("'%s' terminated by an unknown signal."),
1572                             cmd);
1573                 }
1574         } else {
1575                 zerror(gettext("'%s' failed for unknown reasons."), cmd);
1576         }
1577 
1578         /*
1579          * Assume a subprocess that died due to a signal or an unknown error
1580          * should be considered an exit code of ZONE_SUBPROC_FATAL, as the
1581          * user will likely need to do some manual cleanup.
1582          */
1583         return (ZONE_SUBPROC_FATAL);
1584 }
1585 
1586 /*
1587  * Various sanity checks; make sure:
1588  * 1. We're in the global zone.
1589  * 2. The calling user has sufficient privilege.
1590  * 3. The target zone is neither the global zone nor anything starting with
1591  *    "SUNW".
1592  * 4a. If we're looking for a 'not running' (i.e., configured or installed)
1593  *     zone, the name service knows about it.
1594  * 4b. For some operations which expect a zone not to be running, that it is
1595  *     not already running (or ready).
1596  */
1597 static int
1598 sanity_check(char *zone, int cmd_num, boolean_t running,
1599     boolean_t unsafe_when_running, boolean_t force)
1600 {
1601         zone_entry_t *zent;
1602         priv_set_t *privset;
1603         zone_state_t state, min_state;
1604         char kernzone[ZONENAME_MAX];
1605         FILE *fp;
1606 
1607         if (getzoneid() != GLOBAL_ZONEID) {
1608                 switch (cmd_num) {
1609                 case CMD_HALT:
1610                         zerror(gettext("use %s to %s this zone."), "halt(1M)",
1611                             cmd_to_str(cmd_num));
1612                         break;
1613                 case CMD_REBOOT:
1614                         zerror(gettext("use %s to %s this zone."),
1615                             "reboot(1M)", cmd_to_str(cmd_num));
1616                         break;
1617                 default:
1618                         zerror(gettext("must be in the global zone to %s a "
1619                             "zone."), cmd_to_str(cmd_num));
1620                         break;
1621                 }
1622                 return (Z_ERR);
1623         }
1624 
1625         if ((privset = priv_allocset()) == NULL) {
1626                 zerror(gettext("%s failed"), "priv_allocset");
1627                 return (Z_ERR);
1628         }
1629 
1630         if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1631                 zerror(gettext("%s failed"), "getppriv");
1632                 priv_freeset(privset);
1633                 return (Z_ERR);
1634         }
1635 
1636         if (priv_isfullset(privset) == B_FALSE) {
1637                 zerror(gettext("only a privileged user may %s a zone."),
1638                     cmd_to_str(cmd_num));
1639                 priv_freeset(privset);
1640                 return (Z_ERR);
1641         }
1642         priv_freeset(privset);
1643 
1644         if (zone == NULL) {
1645                 zerror(gettext("no zone specified"));
1646                 return (Z_ERR);
1647         }
1648 
1649         if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
1650                 zerror(gettext("%s operation is invalid for the global zone."),
1651                     cmd_to_str(cmd_num));
1652                 return (Z_ERR);
1653         }
1654 
1655         if (strncmp(zone, "SUNW", 4) == 0) {
1656                 zerror(gettext("%s operation is invalid for zones starting "
1657                     "with SUNW."), cmd_to_str(cmd_num));
1658                 return (Z_ERR);
1659         }
1660 
1661         if (!zonecfg_in_alt_root()) {
1662                 zent = lookup_running_zone(zone);
1663         } else if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL) {
1664                 zent = NULL;
1665         } else {
1666                 if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(),
1667                     kernzone, sizeof (kernzone)) == 0)
1668                         zent = lookup_running_zone(kernzone);
1669                 else
1670                         zent = NULL;
1671                 zonecfg_close_scratch(fp);
1672         }
1673 
1674         /*
1675          * Look up from the kernel for 'running' zones.
1676          */
1677         if (running && !force) {
1678                 if (zent == NULL) {
1679                         zerror(gettext("not running"));
1680                         return (Z_ERR);
1681                 }
1682         } else {
1683                 int err;
1684 
1685                 if (unsafe_when_running && zent != NULL) {
1686                         /* check whether the zone is ready or running */
1687                         if ((err = zone_get_state(zent->zname,
1688                             &zent->zstate_num)) != Z_OK) {
1689                                 errno = err;
1690                                 zperror2(zent->zname,
1691                                     gettext("could not get state"));
1692                                 /* can't tell, so hedge */
1693                                 zent->zstate_str = "ready/running";
1694                         } else {
1695                                 zent->zstate_str =
1696                                     zone_state_str(zent->zstate_num);
1697                         }
1698                         zerror(gettext("%s operation is invalid for %s zones."),
1699                             cmd_to_str(cmd_num), zent->zstate_str);
1700                         return (Z_ERR);
1701                 }
1702                 if ((err = zone_get_state(zone, &state)) != Z_OK) {
1703                         errno = err;
1704                         zperror2(zone, gettext("could not get state"));
1705                         return (Z_ERR);
1706                 }
1707                 switch (cmd_num) {
1708                 case CMD_UNINSTALL:
1709                         if (state == ZONE_STATE_CONFIGURED) {
1710                                 zerror(gettext("is already in state '%s'."),
1711                                     zone_state_str(ZONE_STATE_CONFIGURED));
1712                                 return (Z_ERR);
1713                         }
1714                         break;
1715                 case CMD_ATTACH:
1716                 case CMD_CLONE:
1717                 case CMD_INSTALL:
1718                         if (state == ZONE_STATE_INSTALLED) {
1719                                 zerror(gettext("is already %s."),
1720                                     zone_state_str(ZONE_STATE_INSTALLED));
1721                                 return (Z_ERR);
1722                         } else if (state == ZONE_STATE_INCOMPLETE) {
1723                                 zerror(gettext("zone is %s; %s required."),
1724                                     zone_state_str(ZONE_STATE_INCOMPLETE),
1725                                     cmd_to_str(CMD_UNINSTALL));
1726                                 return (Z_ERR);
1727                         }
1728                         break;
1729                 case CMD_DETACH:
1730                 case CMD_MOVE:
1731                 case CMD_READY:
1732                 case CMD_BOOT:
1733                 case CMD_MOUNT:
1734                 case CMD_MARK:
1735                         if ((cmd_num == CMD_BOOT || cmd_num == CMD_MOUNT) &&
1736                             force)
1737                                 min_state = ZONE_STATE_INCOMPLETE;
1738                         else
1739                                 min_state = ZONE_STATE_INSTALLED;
1740 
1741                         if (force && cmd_num == CMD_BOOT && is_native_zone) {
1742                                 zerror(gettext("Only branded zones may be "
1743                                     "force-booted."));
1744                                 return (Z_ERR);
1745                         }
1746 
1747                         if (state < min_state) {
1748                                 zerror(gettext("must be %s before %s."),
1749                                     zone_state_str(min_state),
1750                                     cmd_to_str(cmd_num));
1751                                 return (Z_ERR);
1752                         }
1753                         break;
1754                 case CMD_VERIFY:
1755                         if (state == ZONE_STATE_INCOMPLETE) {
1756                                 zerror(gettext("zone is %s; %s required."),
1757                                     zone_state_str(ZONE_STATE_INCOMPLETE),
1758                                     cmd_to_str(CMD_UNINSTALL));
1759                                 return (Z_ERR);
1760                         }
1761                         break;
1762                 case CMD_UNMOUNT:
1763                         if (state != ZONE_STATE_MOUNTED) {
1764                                 zerror(gettext("must be %s before %s."),
1765                                     zone_state_str(ZONE_STATE_MOUNTED),
1766                                     cmd_to_str(cmd_num));
1767                                 return (Z_ERR);
1768                         }
1769                         break;
1770                 }
1771         }
1772         return (Z_OK);
1773 }
1774 
1775 static int
1776 halt_func(int argc, char *argv[])
1777 {
1778         zone_cmd_arg_t zarg;
1779         int arg;
1780 
1781         if (zonecfg_in_alt_root()) {
1782                 zerror(gettext("cannot halt zone in alternate root"));
1783                 return (Z_ERR);
1784         }
1785 
1786         optind = 0;
1787         if ((arg = getopt(argc, argv, "?")) != EOF) {
1788                 switch (arg) {
1789                 case '?':
1790                         sub_usage(SHELP_HALT, CMD_HALT);
1791                         return (optopt == '?' ? Z_OK : Z_USAGE);
1792                 default:
1793                         sub_usage(SHELP_HALT, CMD_HALT);
1794                         return (Z_USAGE);
1795                 }
1796         }
1797         if (argc > optind) {
1798                 sub_usage(SHELP_HALT, CMD_HALT);
1799                 return (Z_USAGE);
1800         }
1801         /*
1802          * zoneadmd should be the one to decide whether or not to proceed,
1803          * so even though it seems that the fourth parameter below should
1804          * perhaps be B_TRUE, it really shouldn't be.
1805          */
1806         if (sanity_check(target_zone, CMD_HALT, B_FALSE, B_FALSE, B_FALSE)
1807             != Z_OK)
1808                 return (Z_ERR);
1809 
1810         /*
1811          * Invoke brand-specific handler.
1812          */
1813         if (invoke_brand_handler(CMD_HALT, argv) != Z_OK)
1814                 return (Z_ERR);
1815 
1816         zarg.cmd = Z_HALT;
1817         return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale,
1818             B_TRUE) == 0) ?  Z_OK : Z_ERR);
1819 }
1820 
1821 static int
1822 reboot_func(int argc, char *argv[])
1823 {
1824         zone_cmd_arg_t zarg;
1825         int arg;
1826 
1827         if (zonecfg_in_alt_root()) {
1828                 zerror(gettext("cannot reboot zone in alternate root"));
1829                 return (Z_ERR);
1830         }
1831 
1832         optind = 0;
1833         if ((arg = getopt(argc, argv, "?")) != EOF) {
1834                 switch (arg) {
1835                 case '?':
1836                         sub_usage(SHELP_REBOOT, CMD_REBOOT);
1837                         return (optopt == '?' ? Z_OK : Z_USAGE);
1838                 default:
1839                         sub_usage(SHELP_REBOOT, CMD_REBOOT);
1840                         return (Z_USAGE);
1841                 }
1842         }
1843 
1844         zarg.bootbuf[0] = '\0';
1845         for (; optind < argc; optind++) {
1846                 if (strlcat(zarg.bootbuf, argv[optind],
1847                     sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) {
1848                         zerror(gettext("Boot argument list too long"));
1849                         return (Z_ERR);
1850                 }
1851                 if (optind < argc - 1)
1852                         if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >=
1853                             sizeof (zarg.bootbuf)) {
1854                                 zerror(gettext("Boot argument list too long"));
1855                                 return (Z_ERR);
1856                         }
1857         }
1858 
1859 
1860         /*
1861          * zoneadmd should be the one to decide whether or not to proceed,
1862          * so even though it seems that the fourth parameter below should
1863          * perhaps be B_TRUE, it really shouldn't be.
1864          */
1865         if (sanity_check(target_zone, CMD_REBOOT, B_TRUE, B_FALSE, B_FALSE)
1866             != Z_OK)
1867                 return (Z_ERR);
1868         if (verify_details(CMD_REBOOT, argv) != Z_OK)
1869                 return (Z_ERR);
1870 
1871         zarg.cmd = Z_REBOOT;
1872         return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) == 0)
1873             ? Z_OK : Z_ERR);
1874 }
1875 
1876 static int
1877 get_hook(brand_handle_t bh, char *cmd, size_t len, int (*bp)(brand_handle_t,
1878     const char *, const char *, char *, size_t), char *zonename, char *zonepath)
1879 {
1880         if (strlcpy(cmd, EXEC_PREFIX, len) >= len)
1881                 return (Z_ERR);
1882 
1883         if (bp(bh, zonename, zonepath, cmd + EXEC_LEN, len - EXEC_LEN) != 0)
1884                 return (Z_ERR);
1885 
1886         if (strlen(cmd) <= EXEC_LEN)
1887                 cmd[0] = '\0';
1888 
1889         return (Z_OK);
1890 }
1891 
1892 static int
1893 verify_brand(zone_dochandle_t handle, int cmd_num, char *argv[])
1894 {
1895         char cmdbuf[MAXPATHLEN];
1896         int err;
1897         char zonepath[MAXPATHLEN];
1898         brand_handle_t bh = NULL;
1899         int status, i;
1900 
1901         /*
1902          * Fetch the verify command from the brand configuration.
1903          * "exec" the command so that the returned status is that of
1904          * the command and not the shell.
1905          */
1906         if (handle == NULL) {
1907                 (void) strlcpy(zonepath, "-", sizeof (zonepath));
1908         } else if ((err = zonecfg_get_zonepath(handle, zonepath,
1909             sizeof (zonepath))) != Z_OK) {
1910                 errno = err;
1911                 zperror(cmd_to_str(cmd_num), B_TRUE);
1912                 return (Z_ERR);
1913         }
1914         if ((bh = brand_open(target_brand)) == NULL) {
1915                 zerror(gettext("missing or invalid brand"));
1916                 return (Z_ERR);
1917         }
1918 
1919         /*
1920          * If the brand has its own verification routine, execute it now.
1921          * The verification routine validates the intended zoneadm
1922          * operation for the specific brand. The zoneadm subcommand and
1923          * all its arguments are passed to the routine.
1924          */
1925         err = get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_verify_adm,
1926             target_zone, zonepath);
1927         brand_close(bh);
1928         if (err != Z_OK)
1929                 return (Z_BRAND_ERROR);
1930         if (cmdbuf[0] == '\0')
1931                 return (Z_OK);
1932 
1933         if (strlcat(cmdbuf, cmd_to_str(cmd_num),
1934             sizeof (cmdbuf)) >= sizeof (cmdbuf))
1935                 return (Z_ERR);
1936 
1937         /* Build the argv string */
1938         i = 0;
1939         while (argv[i] != NULL) {
1940                 if ((strlcat(cmdbuf, " ",
1941                     sizeof (cmdbuf)) >= sizeof (cmdbuf)) ||
1942                     (strlcat(cmdbuf, argv[i++],
1943                     sizeof (cmdbuf)) >= sizeof (cmdbuf)))
1944                         return (Z_ERR);
1945         }
1946 
1947         if (zoneadm_is_nested)
1948                 status = do_subproc(cmdbuf);
1949         else
1950                 status = do_subproc_interactive(cmdbuf);
1951         err = subproc_status(gettext("brand-specific verification"),
1952             status, B_FALSE);
1953 
1954         return ((err == ZONE_SUBPROC_OK) ? Z_OK : Z_BRAND_ERROR);
1955 }
1956 
1957 static int
1958 verify_rctls(zone_dochandle_t handle)
1959 {
1960         struct zone_rctltab rctltab;
1961         size_t rbs = rctlblk_size();
1962         rctlblk_t *rctlblk;
1963         int error = Z_INVAL;
1964 
1965         if ((rctlblk = malloc(rbs)) == NULL) {
1966                 zerror(gettext("failed to allocate %lu bytes: %s"), rbs,
1967                     strerror(errno));
1968                 return (Z_NOMEM);
1969         }
1970 
1971         if (zonecfg_setrctlent(handle) != Z_OK) {
1972                 zerror(gettext("zonecfg_setrctlent failed"));
1973                 free(rctlblk);
1974                 return (error);
1975         }
1976 
1977         rctltab.zone_rctl_valptr = NULL;
1978         while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
1979                 struct zone_rctlvaltab *rctlval;
1980                 const char *name = rctltab.zone_rctl_name;
1981 
1982                 if (!zonecfg_is_rctl(name)) {
1983                         zerror(gettext("WARNING: Ignoring unrecognized rctl "
1984                             "'%s'."),  name);
1985                         zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
1986                         rctltab.zone_rctl_valptr = NULL;
1987                         continue;
1988                 }
1989 
1990                 for (rctlval = rctltab.zone_rctl_valptr; rctlval != NULL;
1991                     rctlval = rctlval->zone_rctlval_next) {
1992                         if (zonecfg_construct_rctlblk(rctlval, rctlblk)
1993                             != Z_OK) {
1994                                 zerror(gettext("invalid rctl value: "
1995                                     "(priv=%s,limit=%s,action%s)"),
1996                                     rctlval->zone_rctlval_priv,
1997                                     rctlval->zone_rctlval_limit,
1998                                     rctlval->zone_rctlval_action);
1999                                 goto out;
2000                         }
2001                         if (!zonecfg_valid_rctl(name, rctlblk)) {
2002                                 zerror(gettext("(priv=%s,limit=%s,action=%s) "
2003                                     "is not a valid value for rctl '%s'"),
2004                                     rctlval->zone_rctlval_priv,
2005                                     rctlval->zone_rctlval_limit,
2006                                     rctlval->zone_rctlval_action,
2007                                     name);
2008                                 goto out;
2009                         }
2010                 }
2011                 zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2012         }
2013         rctltab.zone_rctl_valptr = NULL;
2014         error = Z_OK;
2015 out:
2016         zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr);
2017         (void) zonecfg_endrctlent(handle);
2018         free(rctlblk);
2019         return (error);
2020 }
2021 
2022 static int
2023 verify_pool(zone_dochandle_t handle)
2024 {
2025         char poolname[MAXPATHLEN];
2026         pool_conf_t *poolconf;
2027         pool_t *pool;
2028         int status;
2029         int error;
2030 
2031         /*
2032          * This ends up being very similar to the check done in zoneadmd.
2033          */
2034         error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
2035         if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
2036                 /*
2037                  * No pool specified.
2038                  */
2039                 return (0);
2040         }
2041         if (error != Z_OK) {
2042                 zperror(gettext("Unable to retrieve pool name from "
2043                     "configuration"), B_TRUE);
2044                 return (error);
2045         }
2046         /*
2047          * Don't do anything if pools aren't enabled.
2048          */
2049         if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
2050                 zerror(gettext("WARNING: pools facility not active; "
2051                     "zone will not be bound to pool '%s'."), poolname);
2052                 return (Z_OK);
2053         }
2054         /*
2055          * Try to provide a sane error message if the requested pool doesn't
2056          * exist.  It isn't clear that pools-related failures should
2057          * necessarily translate to a failure to verify the zone configuration,
2058          * hence they are not considered errors.
2059          */
2060         if ((poolconf = pool_conf_alloc()) == NULL) {
2061                 zerror(gettext("WARNING: pool_conf_alloc failed; "
2062                     "using default pool"));
2063                 return (Z_OK);
2064         }
2065         if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
2066             PO_SUCCESS) {
2067                 zerror(gettext("WARNING: pool_conf_open failed; "
2068                     "using default pool"));
2069                 pool_conf_free(poolconf);
2070                 return (Z_OK);
2071         }
2072         pool = pool_get_pool(poolconf, poolname);
2073         (void) pool_conf_close(poolconf);
2074         pool_conf_free(poolconf);
2075         if (pool == NULL) {
2076                 zerror(gettext("WARNING: pool '%s' not found. "
2077                     "using default pool"), poolname);
2078         }
2079 
2080         return (Z_OK);
2081 }
2082 
2083 static int
2084 verify_ipd(zone_dochandle_t handle)
2085 {
2086         int return_code = Z_OK;
2087         struct zone_fstab fstab;
2088         struct stat st;
2089         char specdir[MAXPATHLEN];
2090 
2091         if (zonecfg_setipdent(handle) != Z_OK) {
2092                 /*
2093                  * TRANSLATION_NOTE
2094                  * inherit-pkg-dirs is a literal that should not be translated.
2095                  */
2096                 (void) fprintf(stderr, gettext("could not verify "
2097                     "inherit-pkg-dirs: unable to enumerate mounts\n"));
2098                 return (Z_ERR);
2099         }
2100         while (zonecfg_getipdent(handle, &fstab) == Z_OK) {
2101                 /*
2102                  * Verify fs_dir exists.
2103                  */
2104                 (void) snprintf(specdir, sizeof (specdir), "%s%s",
2105                     zonecfg_get_root(), fstab.zone_fs_dir);
2106                 if (stat(specdir, &st) != 0) {
2107                         /*
2108                          * TRANSLATION_NOTE
2109                          * inherit-pkg-dir is a literal that should not be
2110                          * translated.
2111                          */
2112                         (void) fprintf(stderr, gettext("could not verify "
2113                             "inherit-pkg-dir %s: %s\n"),
2114                             fstab.zone_fs_dir, strerror(errno));
2115                         return_code = Z_ERR;
2116                 }
2117                 if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) {
2118                         /*
2119                          * TRANSLATION_NOTE
2120                          * inherit-pkg-dir and NFS are literals that should
2121                          * not be translated.
2122                          */
2123                         (void) fprintf(stderr, gettext("cannot verify "
2124                             "inherit-pkg-dir %s: NFS mounted file system.\n"
2125                             "\tA local file system must be used.\n"),
2126                             fstab.zone_fs_dir);
2127                         return_code = Z_ERR;
2128                 }
2129         }
2130         (void) zonecfg_endipdent(handle);
2131 
2132         return (return_code);
2133 }
2134 
2135 /*
2136  * Verify that the special device/file system exists and is valid.
2137  */
2138 static int
2139 verify_fs_special(struct zone_fstab *fstab)
2140 {
2141         struct stat64 st;
2142 
2143         /*
2144          * This validation is really intended for standard zone administration.
2145          * If we are in a mini-root or some other upgrade situation where
2146          * we are using the scratch zone, just by-pass this.
2147          */
2148         if (zonecfg_in_alt_root())
2149                 return (Z_OK);
2150 
2151         if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0)
2152                 return (verify_fs_zfs(fstab));
2153 
2154         if (stat64(fstab->zone_fs_special, &st) != 0) {
2155                 (void) fprintf(stderr, gettext("could not verify fs "
2156                     "%s: could not access %s: %s\n"), fstab->zone_fs_dir,
2157                     fstab->zone_fs_special, strerror(errno));
2158                 return (Z_ERR);
2159         }
2160 
2161         if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) {
2162                 /*
2163                  * TRANSLATION_NOTE
2164                  * fs and NFS are literals that should
2165                  * not be translated.
2166                  */
2167                 (void) fprintf(stderr, gettext("cannot verify "
2168                     "fs %s: NFS mounted file system.\n"
2169                     "\tA local file system must be used.\n"),
2170                     fstab->zone_fs_special);
2171                 return (Z_ERR);
2172         }
2173 
2174         return (Z_OK);
2175 }
2176 
2177 static int
2178 isregfile(const char *path)
2179 {
2180         struct stat64 st;
2181 
2182         if (stat64(path, &st) == -1)
2183                 return (-1);
2184 
2185         return (S_ISREG(st.st_mode));
2186 }
2187 
2188 static int
2189 verify_filesystems(zone_dochandle_t handle)
2190 {
2191         int return_code = Z_OK;
2192         struct zone_fstab fstab;
2193         char cmdbuf[MAXPATHLEN];
2194         struct stat st;
2195 
2196         /*
2197          * No need to verify inherit-pkg-dir fs types, as their type is
2198          * implicitly lofs, which is known.  Therefore, the types are only
2199          * verified for regular file systems below.
2200          *
2201          * Since the actual mount point is not known until the dependent mounts
2202          * are performed, we don't attempt any path validation here: that will
2203          * happen later when zoneadmd actually does the mounts.
2204          */
2205         if (zonecfg_setfsent(handle) != Z_OK) {
2206                 (void) fprintf(stderr, gettext("could not verify file systems: "
2207                     "unable to enumerate mounts\n"));
2208                 return (Z_ERR);
2209         }
2210         while (zonecfg_getfsent(handle, &fstab) == Z_OK) {
2211                 if (!zonecfg_valid_fs_type(fstab.zone_fs_type)) {
2212                         (void) fprintf(stderr, gettext("cannot verify fs %s: "
2213                             "type %s is not allowed.\n"), fstab.zone_fs_dir,
2214                             fstab.zone_fs_type);
2215                         return_code = Z_ERR;
2216                         goto next_fs;
2217                 }
2218                 /*
2219                  * Verify /usr/lib/fs/<fstype>/mount exists.
2220                  */
2221                 if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/mount",
2222                     fstab.zone_fs_type) > sizeof (cmdbuf)) {
2223                         (void) fprintf(stderr, gettext("cannot verify fs %s: "
2224                             "type %s is too long.\n"), fstab.zone_fs_dir,
2225                             fstab.zone_fs_type);
2226                         return_code = Z_ERR;
2227                         goto next_fs;
2228                 }
2229                 if (stat(cmdbuf, &st) != 0) {
2230                         (void) fprintf(stderr, gettext("could not verify fs "
2231                             "%s: could not access %s: %s\n"), fstab.zone_fs_dir,
2232                             cmdbuf, strerror(errno));
2233                         return_code = Z_ERR;
2234                         goto next_fs;
2235                 }
2236                 if (!S_ISREG(st.st_mode)) {
2237                         (void) fprintf(stderr, gettext("could not verify fs "
2238                             "%s: %s is not a regular file\n"),
2239                             fstab.zone_fs_dir, cmdbuf);
2240                         return_code = Z_ERR;
2241                         goto next_fs;
2242                 }
2243                 /*
2244                  * If zone_fs_raw is set, verify that there's an fsck
2245                  * binary for it.  If zone_fs_raw is not set, and it's
2246                  * not a regular file (lofi mount), and there's an fsck
2247                  * binary for it, complain.
2248                  */
2249                 if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/fsck",
2250                     fstab.zone_fs_type) > sizeof (cmdbuf)) {
2251                         (void) fprintf(stderr, gettext("cannot verify fs %s: "
2252                             "type %s is too long.\n"), fstab.zone_fs_dir,
2253                             fstab.zone_fs_type);
2254                         return_code = Z_ERR;
2255                         goto next_fs;
2256                 }
2257                 if (fstab.zone_fs_raw[0] != '\0' &&
2258                     (stat(cmdbuf, &st) != 0 || !S_ISREG(st.st_mode))) {
2259                         (void) fprintf(stderr, gettext("cannot verify fs %s: "
2260                             "'raw' device specified but "
2261                             "no fsck executable exists for %s\n"),
2262                             fstab.zone_fs_dir, fstab.zone_fs_type);
2263                         return_code = Z_ERR;
2264                         goto next_fs;
2265                 } else if (fstab.zone_fs_raw[0] == '\0' &&
2266                     stat(cmdbuf, &st) == 0 &&
2267                     isregfile(fstab.zone_fs_special) != 1) {
2268                         (void) fprintf(stderr, gettext("could not verify fs "
2269                             "%s: must specify 'raw' device for %s "
2270                             "file systems\n"),
2271                             fstab.zone_fs_dir, fstab.zone_fs_type);
2272                         return_code = Z_ERR;
2273                         goto next_fs;
2274                 }
2275 
2276                 /* Verify fs_special. */
2277                 if ((return_code = verify_fs_special(&fstab)) != Z_OK)
2278                         goto next_fs;
2279 
2280                 /* Verify fs_raw. */
2281                 if (fstab.zone_fs_raw[0] != '\0' &&
2282                     stat(fstab.zone_fs_raw, &st) != 0) {
2283                         /*
2284                          * TRANSLATION_NOTE
2285                          * fs is a literal that should not be translated.
2286                          */
2287                         (void) fprintf(stderr, gettext("could not verify fs "
2288                             "%s: could not access %s: %s\n"), fstab.zone_fs_dir,
2289                             fstab.zone_fs_raw, strerror(errno));
2290                         return_code = Z_ERR;
2291                         goto next_fs;
2292                 }
2293 next_fs:
2294                 zonecfg_free_fs_option_list(fstab.zone_fs_options);
2295         }
2296         (void) zonecfg_endfsent(handle);
2297 
2298         return (return_code);
2299 }
2300 
2301 static int
2302 verify_limitpriv(zone_dochandle_t handle)
2303 {
2304         char *privname = NULL;
2305         int err;
2306         priv_set_t *privs;
2307 
2308         if ((privs = priv_allocset()) == NULL) {
2309                 zperror(gettext("failed to allocate privilege set"), B_FALSE);
2310                 return (Z_NOMEM);
2311         }
2312         err = zonecfg_get_privset(handle, privs, &privname);
2313         switch (err) {
2314         case Z_OK:
2315                 break;
2316         case Z_PRIV_PROHIBITED:
2317                 (void) fprintf(stderr, gettext("privilege \"%s\" is not "
2318                     "permitted within the zone's privilege set\n"), privname);
2319                 break;
2320         case Z_PRIV_REQUIRED:
2321                 (void) fprintf(stderr, gettext("required privilege \"%s\" is "
2322                     "missing from the zone's privilege set\n"), privname);
2323                 break;
2324         case Z_PRIV_UNKNOWN:
2325                 (void) fprintf(stderr, gettext("unknown privilege \"%s\" "
2326                     "specified in the zone's privilege set\n"), privname);
2327                 break;
2328         default:
2329                 zperror(
2330                     gettext("failed to determine the zone's privilege set"),
2331                     B_TRUE);
2332                 break;
2333         }
2334         free(privname);
2335         priv_freeset(privs);
2336         return (err);
2337 }
2338 
2339 static void
2340 free_local_netifs(int if_cnt, struct net_if **if_list)
2341 {
2342         int             i;
2343 
2344         for (i = 0; i < if_cnt; i++) {
2345                 free(if_list[i]->name);
2346                 free(if_list[i]);
2347         }
2348         free(if_list);
2349 }
2350 
2351 /*
2352  * Get a list of the network interfaces, along with their address families,
2353  * that are plumbed in the global zone.  See if_tcp(7p) for a description
2354  * of the ioctls used here.
2355  */
2356 static int
2357 get_local_netifs(int *if_cnt, struct net_if ***if_list)
2358 {
2359         int             s;
2360         int             i;
2361         int             res = Z_OK;
2362         int             space_needed;
2363         int             cnt = 0;
2364         struct          lifnum if_num;
2365         struct          lifconf if_conf;
2366         struct          lifreq *if_reqp;
2367         char            *if_buf;
2368         struct net_if   **local_ifs = NULL;
2369 
2370         *if_cnt = 0;
2371         *if_list = NULL;
2372 
2373         if ((s = socket(SOCKET_AF(AF_INET), SOCK_DGRAM, 0)) < 0)
2374                 return (Z_ERR);
2375 
2376         /*
2377          * Come back here in the unlikely event that the number of interfaces
2378          * increases between the time we get the count and the time we do the
2379          * SIOCGLIFCONF ioctl.
2380          */
2381 retry:
2382         /* Get the number of interfaces. */
2383         if_num.lifn_family = AF_UNSPEC;
2384         if_num.lifn_flags = LIFC_NOXMIT;
2385         if (ioctl(s, SIOCGLIFNUM, &if_num) < 0) {
2386                 (void) close(s);
2387                 return (Z_ERR);
2388         }
2389 
2390         /* Get the interface configuration list. */
2391         space_needed = if_num.lifn_count * sizeof (struct lifreq);
2392         if ((if_buf = malloc(space_needed)) == NULL) {
2393                 (void) close(s);
2394                 return (Z_ERR);
2395         }
2396         if_conf.lifc_family = AF_UNSPEC;
2397         if_conf.lifc_flags = LIFC_NOXMIT;
2398         if_conf.lifc_len = space_needed;
2399         if_conf.lifc_buf = if_buf;
2400         if (ioctl(s, SIOCGLIFCONF, &if_conf) < 0) {
2401                 free(if_buf);
2402                 /*
2403                  * SIOCGLIFCONF returns EINVAL if the buffer we passed in is
2404                  * too small.  In this case go back and get the new if cnt.
2405                  */
2406                 if (errno == EINVAL)
2407                         goto retry;
2408 
2409                 (void) close(s);
2410                 return (Z_ERR);
2411         }
2412         (void) close(s);
2413 
2414         /* Get the name and address family for each interface. */
2415         if_reqp = if_conf.lifc_req;
2416         for (i = 0; i < (if_conf.lifc_len / sizeof (struct lifreq)); i++) {
2417                 struct net_if   **p;
2418                 struct lifreq   req;
2419 
2420                 if (strcmp(LOOPBACK_IF, if_reqp->lifr_name) == 0) {
2421                         if_reqp++;
2422                         continue;
2423                 }
2424 
2425                 if ((s = socket(SOCKET_AF(if_reqp->lifr_addr.ss_family),
2426                     SOCK_DGRAM, 0)) == -1) {
2427                         res = Z_ERR;
2428                         break;
2429                 }
2430 
2431                 (void) strncpy(req.lifr_name, if_reqp->lifr_name,
2432                     sizeof (req.lifr_name));
2433                 if (ioctl(s, SIOCGLIFADDR, &req) < 0) {
2434                         (void) close(s);
2435                         if_reqp++;
2436                         continue;
2437                 }
2438 
2439                 if ((p = (struct net_if **)realloc(local_ifs,
2440                     sizeof (struct net_if *) * (cnt + 1))) == NULL) {
2441                         res = Z_ERR;
2442                         break;
2443                 }
2444                 local_ifs = p;
2445 
2446                 if ((local_ifs[cnt] = malloc(sizeof (struct net_if))) == NULL) {
2447                         res = Z_ERR;
2448                         break;
2449                 }
2450 
2451                 if ((local_ifs[cnt]->name = strdup(if_reqp->lifr_name))
2452                     == NULL) {
2453                         free(local_ifs[cnt]);
2454                         res = Z_ERR;
2455                         break;
2456                 }
2457                 local_ifs[cnt]->af = req.lifr_addr.ss_family;
2458                 cnt++;
2459 
2460                 (void) close(s);
2461                 if_reqp++;
2462         }
2463 
2464         free(if_buf);
2465 
2466         if (res != Z_OK) {
2467                 free_local_netifs(cnt, local_ifs);
2468         } else {
2469                 *if_cnt = cnt;
2470                 *if_list = local_ifs;
2471         }
2472 
2473         return (res);
2474 }
2475 
2476 static char *
2477 af2str(int af)
2478 {
2479         switch (af) {
2480         case AF_INET:
2481                 return ("IPv4");
2482         case AF_INET6:
2483                 return ("IPv6");
2484         default:
2485                 return ("Unknown");
2486         }
2487 }
2488 
2489 /*
2490  * Cross check the network interface name and address family with the
2491  * interfaces that are set up in the global zone so that we can print the
2492  * appropriate error message.
2493  */
2494 static void
2495 print_net_err(char *phys, char *addr, int af, char *msg)
2496 {
2497         int             i;
2498         int             local_if_cnt = 0;
2499         struct net_if   **local_ifs = NULL;
2500         boolean_t       found_if = B_FALSE;
2501         boolean_t       found_af = B_FALSE;
2502 
2503         if (get_local_netifs(&local_if_cnt, &local_ifs) != Z_OK) {
2504                 (void) fprintf(stderr,
2505                     gettext("could not verify %s %s=%s %s=%s\n\t%s\n"),
2506                     "net", "address", addr, "physical", phys, msg);
2507                 return;
2508         }
2509 
2510         for (i = 0; i < local_if_cnt; i++) {
2511                 if (strcmp(phys, local_ifs[i]->name) == 0) {
2512                         found_if = B_TRUE;
2513                         if (af == local_ifs[i]->af) {
2514                                 found_af = B_TRUE;
2515                                 break;
2516                         }
2517                 }
2518         }
2519 
2520         free_local_netifs(local_if_cnt, local_ifs);
2521 
2522         if (!found_if) {
2523                 (void) fprintf(stderr,
2524                     gettext("could not verify %s %s=%s\n\t"
2525                     "network interface %s is not plumbed in the global zone\n"),
2526                     "net", "physical", phys, phys);
2527                 return;
2528         }
2529 
2530         /*
2531          * Print this error if we were unable to find the address family
2532          * for this interface.  If the af variable is not initialized to
2533          * to something meaningful by the caller (not AF_UNSPEC) then we
2534          * also skip this message since it wouldn't be informative.
2535          */
2536         if (!found_af && af != AF_UNSPEC) {
2537                 (void) fprintf(stderr,
2538                     gettext("could not verify %s %s=%s %s=%s\n\tthe %s address "
2539                     "family is not configured on this network interface in "
2540                     "the\n\tglobal zone\n"),
2541                     "net", "address", addr, "physical", phys, af2str(af));
2542                 return;
2543         }
2544 
2545         (void) fprintf(stderr,
2546             gettext("could not verify %s %s=%s %s=%s\n\t%s\n"),
2547             "net", "address", addr, "physical", phys, msg);
2548 }
2549 
2550 static int
2551 verify_handle(int cmd_num, zone_dochandle_t handle, char *argv[])
2552 {
2553         struct zone_nwiftab nwiftab;
2554         int return_code = Z_OK;
2555         int err;
2556         boolean_t in_alt_root;
2557         zone_iptype_t iptype;
2558         dlpi_handle_t dh;
2559 
2560         in_alt_root = zonecfg_in_alt_root();
2561         if (in_alt_root)
2562                 goto no_net;
2563 
2564         if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK) {
2565                 errno = err;
2566                 zperror(cmd_to_str(cmd_num), B_TRUE);
2567                 zonecfg_fini_handle(handle);
2568                 return (Z_ERR);
2569         }
2570         if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
2571                 errno = err;
2572                 zperror(cmd_to_str(cmd_num), B_TRUE);
2573                 zonecfg_fini_handle(handle);
2574                 return (Z_ERR);
2575         }
2576         while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
2577                 struct lifreq lifr;
2578                 sa_family_t af = AF_UNSPEC;
2579                 char dl_owner_zname[ZONENAME_MAX];
2580                 zoneid_t dl_owner_zid;
2581                 zoneid_t target_zid;
2582                 int res;
2583 
2584                 /* skip any loopback interfaces */
2585                 if (strcmp(nwiftab.zone_nwif_physical, "lo0") == 0)
2586                         continue;
2587                 switch (iptype) {
2588                 case ZS_SHARED:
2589                         if ((res = zonecfg_valid_net_address(
2590                             nwiftab.zone_nwif_address, &lifr)) != Z_OK) {
2591                                 print_net_err(nwiftab.zone_nwif_physical,
2592                                     nwiftab.zone_nwif_address, af,
2593                                     zonecfg_strerror(res));
2594                                 return_code = Z_ERR;
2595                                 continue;
2596                         }
2597                         af = lifr.lifr_addr.ss_family;
2598                         if (!zonecfg_ifname_exists(af,
2599                             nwiftab.zone_nwif_physical)) {
2600                                 /*
2601                                  * The interface failed to come up. We continue
2602                                  * on anyway for the sake of consistency: a
2603                                  * zone is not shut down if the interface fails
2604                                  * any time after boot, nor does the global zone
2605                                  * fail to boot if an interface fails.
2606                                  */
2607                                 (void) fprintf(stderr,
2608                                     gettext("WARNING: skipping network "
2609                                     "interface '%s' which may not be "
2610                                     "present/plumbed in the global "
2611                                     "zone.\n"),
2612                                     nwiftab.zone_nwif_physical);
2613                         }
2614                         break;
2615                 case ZS_EXCLUSIVE:
2616                         /* Warning if it exists for either IPv4 or IPv6 */
2617 
2618                         if (zonecfg_ifname_exists(AF_INET,
2619                             nwiftab.zone_nwif_physical) ||
2620                             zonecfg_ifname_exists(AF_INET6,
2621                             nwiftab.zone_nwif_physical)) {
2622                                 (void) fprintf(stderr,
2623                                     gettext("WARNING: skipping network "
2624                                     "interface '%s' which is used in the "
2625                                     "global zone.\n"),
2626                                     nwiftab.zone_nwif_physical);
2627                                 break;
2628                         }
2629 
2630                         /*
2631                          * Verify that the physical interface can be opened.
2632                          */
2633                         err = dlpi_open(nwiftab.zone_nwif_physical, &dh, 0);
2634                         if (err != DLPI_SUCCESS) {
2635                                 (void) fprintf(stderr,
2636                                     gettext("WARNING: skipping network "
2637                                     "interface '%s' which cannot be opened: "
2638                                     "dlpi error (%s).\n"),
2639                                     nwiftab.zone_nwif_physical,
2640                                     dlpi_strerror(err));
2641                                 break;
2642                         } else {
2643                                 dlpi_close(dh);
2644                         }
2645                         /*
2646                          * Verify whether the physical interface is already
2647                          * used by a zone.
2648                          */
2649                         dl_owner_zid = ALL_ZONES;
2650                         if (zone_check_datalink(&dl_owner_zid,
2651                             nwiftab.zone_nwif_physical) != 0)
2652                                 break;
2653 
2654                         /*
2655                          * If the zone being verified is
2656                          * running and owns the interface
2657                          */
2658                         target_zid = getzoneidbyname(target_zone);
2659                         if (target_zid == dl_owner_zid)
2660                                 break;
2661 
2662                         /* Zone id match failed, use name to check */
2663                         if (getzonenamebyid(dl_owner_zid, dl_owner_zname,
2664                             ZONENAME_MAX) < 0) {
2665                                 /* No name, show ID instead */
2666                                 (void) snprintf(dl_owner_zname, ZONENAME_MAX,
2667                                     "<%d>", dl_owner_zid);
2668                         } else if (strcmp(dl_owner_zname, target_zone) == 0)
2669                                 break;
2670 
2671                         /*
2672                          * Note here we only report a warning that
2673                          * the interface is already in use by another
2674                          * running zone, and the verify process just
2675                          * goes on, if the interface is still in use
2676                          * when this zone really boots up, zoneadmd
2677                          * will find it. If the name of the zone which
2678                          * owns this interface cannot be determined,
2679                          * then it is not possible to determine if there
2680                          * is a conflict so just report it as a warning.
2681                          */
2682                         (void) fprintf(stderr,
2683                             gettext("WARNING: skipping network interface "
2684                             "'%s' which is used by the non-global zone "
2685                             "'%s'.\n"), nwiftab.zone_nwif_physical,
2686                             dl_owner_zname);
2687                         break;
2688                 }
2689         }
2690         (void) zonecfg_endnwifent(handle);
2691 no_net:
2692 
2693         /* verify that lofs has not been excluded from the kernel */
2694         if (!(cmd_num == CMD_DETACH || cmd_num == CMD_ATTACH ||
2695             cmd_num == CMD_MOVE || cmd_num == CMD_CLONE) &&
2696             modctl(MODLOAD, 1, "fs/lofs", NULL) != 0) {
2697                 if (errno == ENXIO)
2698                         (void) fprintf(stderr, gettext("could not verify "
2699                             "lofs(7FS): possibly excluded in /etc/system\n"));
2700                 else
2701                         (void) fprintf(stderr, gettext("could not verify "
2702                             "lofs(7FS): %s\n"), strerror(errno));
2703                 return_code = Z_ERR;
2704         }
2705 
2706         if (verify_filesystems(handle) != Z_OK)
2707                 return_code = Z_ERR;
2708         if (verify_ipd(handle) != Z_OK)
2709                 return_code = Z_ERR;
2710         if (!in_alt_root && verify_rctls(handle) != Z_OK)
2711                 return_code = Z_ERR;
2712         if (!in_alt_root && verify_pool(handle) != Z_OK)
2713                 return_code = Z_ERR;
2714         if (!in_alt_root && verify_brand(handle, cmd_num, argv) != Z_OK)
2715                 return_code = Z_ERR;
2716         if (!in_alt_root && verify_datasets(handle) != Z_OK)
2717                 return_code = Z_ERR;
2718 
2719         /*
2720          * As the "mount" command is used for patching/upgrading of zones
2721          * or other maintenance processes, the zone's privilege set is not
2722          * checked in this case.  Instead, the default, safe set of
2723          * privileges will be used when this zone is created in the
2724          * kernel.
2725          */
2726         if (!in_alt_root && cmd_num != CMD_MOUNT &&
2727             verify_limitpriv(handle) != Z_OK)
2728                 return_code = Z_ERR;
2729 
2730         return (return_code);
2731 }
2732 
2733 static int
2734 verify_details(int cmd_num, char *argv[])
2735 {
2736         zone_dochandle_t handle;
2737         char zonepath[MAXPATHLEN], checkpath[MAXPATHLEN];
2738         int return_code = Z_OK;
2739         int err;
2740 
2741         if ((handle = zonecfg_init_handle()) == NULL) {
2742                 zperror(cmd_to_str(cmd_num), B_TRUE);
2743                 return (Z_ERR);
2744         }
2745         if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
2746                 errno = err;
2747                 zperror(cmd_to_str(cmd_num), B_TRUE);
2748                 zonecfg_fini_handle(handle);
2749                 return (Z_ERR);
2750         }
2751         if ((err = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath))) !=
2752             Z_OK) {
2753                 errno = err;
2754                 zperror(cmd_to_str(cmd_num), B_TRUE);
2755                 zonecfg_fini_handle(handle);
2756                 return (Z_ERR);
2757         }
2758         /*
2759          * zonecfg_get_zonepath() gets its data from the XML repository.
2760          * Verify this against the index file, which is checked first by
2761          * zone_get_zonepath().  If they don't match, bail out.
2762          */
2763         if ((err = zone_get_zonepath(target_zone, checkpath,
2764             sizeof (checkpath))) != Z_OK) {
2765                 errno = err;
2766                 zperror2(target_zone, gettext("could not get zone path"));
2767                 zonecfg_fini_handle(handle);
2768                 return (Z_ERR);
2769         }
2770         if (strcmp(zonepath, checkpath) != 0) {
2771                 /*
2772                  * TRANSLATION_NOTE
2773                  * XML and zonepath are literals that should not be translated.
2774                  */
2775                 (void) fprintf(stderr, gettext("The XML repository has "
2776                     "zonepath '%s',\nbut the index file has zonepath '%s'.\n"
2777                     "These must match, so fix the incorrect entry.\n"),
2778                     zonepath, checkpath);
2779                 zonecfg_fini_handle(handle);
2780                 return (Z_ERR);
2781         }
2782         if (validate_zonepath(zonepath, cmd_num) != Z_OK) {
2783                 (void) fprintf(stderr, gettext("could not verify zonepath %s "
2784                     "because of the above errors.\n"), zonepath);
2785                 return_code = Z_ERR;
2786         }
2787 
2788         if (verify_handle(cmd_num, handle, argv) != Z_OK)
2789                 return_code = Z_ERR;
2790 
2791         zonecfg_fini_handle(handle);
2792         if (return_code == Z_ERR)
2793                 (void) fprintf(stderr,
2794                     gettext("%s: zone %s failed to verify\n"),
2795                     execname, target_zone);
2796         return (return_code);
2797 }
2798 
2799 static int
2800 verify_func(int argc, char *argv[])
2801 {
2802         int arg;
2803 
2804         optind = 0;
2805         if ((arg = getopt(argc, argv, "?")) != EOF) {
2806                 switch (arg) {
2807                 case '?':
2808                         sub_usage(SHELP_VERIFY, CMD_VERIFY);
2809                         return (optopt == '?' ? Z_OK : Z_USAGE);
2810                 default:
2811                         sub_usage(SHELP_VERIFY, CMD_VERIFY);
2812                         return (Z_USAGE);
2813                 }
2814         }
2815         if (argc > optind) {
2816                 sub_usage(SHELP_VERIFY, CMD_VERIFY);
2817                 return (Z_USAGE);
2818         }
2819         if (sanity_check(target_zone, CMD_VERIFY, B_FALSE, B_FALSE, B_FALSE)
2820             != Z_OK)
2821                 return (Z_ERR);
2822         return (verify_details(CMD_VERIFY, argv));
2823 }
2824 
2825 static int
2826 addoptions(char *buf, char *argv[], size_t len)
2827 {
2828         int i = 0;
2829 
2830         if (buf[0] == '\0')
2831                 return (Z_OK);
2832 
2833         while (argv[i] != NULL) {
2834                 if (strlcat(buf, " ", len) >= len ||
2835                     strlcat(buf, argv[i++], len) >= len) {
2836                         zerror("Command line too long");
2837                         return (Z_ERR);
2838                 }
2839         }
2840 
2841         return (Z_OK);
2842 }
2843 
2844 static int
2845 addopt(char *buf, int opt, char *optarg, size_t bufsize)
2846 {
2847         char optstring[4];
2848 
2849         if (opt > 0)
2850                 (void) sprintf(optstring, " -%c", opt);
2851         else
2852                 (void) strcpy(optstring, " ");
2853 
2854         if ((strlcat(buf, optstring, bufsize) > bufsize))
2855                 return (Z_ERR);
2856 
2857         if ((optarg != NULL) && (strlcat(buf, optarg, bufsize) > bufsize))
2858                 return (Z_ERR);
2859 
2860         return (Z_OK);
2861 }
2862 
2863 /* ARGSUSED */
2864 static int
2865 install_func(int argc, char *argv[])
2866 {
2867         char cmdbuf[MAXPATHLEN];
2868         char postcmdbuf[MAXPATHLEN];
2869         int lockfd;
2870         int arg, err, subproc_err;
2871         char zonepath[MAXPATHLEN];
2872         brand_handle_t bh = NULL;
2873         int status;
2874         boolean_t nodataset = B_FALSE;
2875         boolean_t do_postinstall = B_FALSE;
2876         boolean_t brand_help = B_FALSE;
2877         char opts[128];
2878 
2879         if (target_zone == NULL) {
2880                 sub_usage(SHELP_INSTALL, CMD_INSTALL);
2881                 return (Z_USAGE);
2882         }
2883 
2884         if (zonecfg_in_alt_root()) {
2885                 zerror(gettext("cannot install zone in alternate root"));
2886                 return (Z_ERR);
2887         }
2888 
2889         if ((err = zone_get_zonepath(target_zone, zonepath,
2890             sizeof (zonepath))) != Z_OK) {
2891                 errno = err;
2892                 zperror2(target_zone, gettext("could not get zone path"));
2893                 return (Z_ERR);
2894         }
2895 
2896         /* Fetch the install command from the brand configuration.  */
2897         if ((bh = brand_open(target_brand)) == NULL) {
2898                 zerror(gettext("missing or invalid brand"));
2899                 return (Z_ERR);
2900         }
2901 
2902         if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_install,
2903             target_zone, zonepath) != Z_OK) {
2904                 zerror("invalid brand configuration: missing install resource");
2905                 brand_close(bh);
2906                 return (Z_ERR);
2907         }
2908 
2909         if (get_hook(bh, postcmdbuf, sizeof (postcmdbuf), brand_get_postinstall,
2910             target_zone, zonepath) != Z_OK) {
2911                 zerror("invalid brand configuration: missing postinstall "
2912                     "resource");
2913                 brand_close(bh);
2914                 return (Z_ERR);
2915         }
2916 
2917         if (postcmdbuf[0] != '\0')
2918                 do_postinstall = B_TRUE;
2919 
2920         (void) strcpy(opts, "?x:");
2921         /*
2922          * Fetch the list of recognized command-line options from
2923          * the brand configuration file.
2924          */
2925         if (brand_get_installopts(bh, opts + strlen(opts),
2926             sizeof (opts) - strlen(opts)) != 0) {
2927                 zerror("invalid brand configuration: missing "
2928                     "install options resource");
2929                 brand_close(bh);
2930                 return (Z_ERR);
2931         }
2932 
2933         brand_close(bh);
2934 
2935         if (cmdbuf[0] == '\0') {
2936                 zerror("Missing brand install command");
2937                 return (Z_ERR);
2938         }
2939 
2940         /* Check the argv string for args we handle internally */
2941         optind = 0;
2942         opterr = 0;
2943         while ((arg = getopt(argc, argv, opts)) != EOF) {
2944                 switch (arg) {
2945                 case '?':
2946                         if (optopt == '?') {
2947                                 sub_usage(SHELP_INSTALL, CMD_INSTALL);
2948                                 brand_help = B_TRUE;
2949                         }
2950                         /* Ignore unknown options - may be brand specific. */
2951                         break;
2952                 case 'x':
2953                         /* Handle this option internally, don't pass to brand */
2954                         if (strcmp(optarg, "nodataset") == 0) {
2955                                 /* Handle this option internally */
2956                                 nodataset = B_TRUE;
2957                         }
2958                         continue;
2959                 default:
2960                         /* Ignore unknown options - may be brand specific. */
2961                         break;
2962                 }
2963 
2964                 /*
2965                  * Append the option to the command line passed to the
2966                  * brand-specific install and postinstall routines.
2967                  */
2968                 if (addopt(cmdbuf, optopt, optarg, sizeof (cmdbuf)) != Z_OK) {
2969                         zerror("Install command line too long");
2970                         return (Z_ERR);
2971                 }
2972                 if (addopt(postcmdbuf, optopt, optarg, sizeof (postcmdbuf))
2973                     != Z_OK) {
2974                         zerror("Post-Install command line too long");
2975                         return (Z_ERR);
2976                 }
2977         }
2978 
2979         for (; optind < argc; optind++) {
2980                 if (addopt(cmdbuf, 0, argv[optind], sizeof (cmdbuf)) != Z_OK) {
2981                         zerror("Install command line too long");
2982                         return (Z_ERR);
2983                 }
2984 
2985                 if (addopt(postcmdbuf, 0, argv[optind], sizeof (postcmdbuf))
2986                     != Z_OK) {
2987                         zerror("Post-Install command line too long");
2988                         return (Z_ERR);
2989                 }
2990         }
2991 
2992         if (!brand_help) {
2993                 if (sanity_check(target_zone, CMD_INSTALL, B_FALSE, B_TRUE,
2994                     B_FALSE) != Z_OK)
2995                         return (Z_ERR);
2996                 if (verify_details(CMD_INSTALL, argv) != Z_OK)
2997                         return (Z_ERR);
2998 
2999                 if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) {
3000                         zerror(gettext("another %s may have an operation in "
3001                             "progress."), "zoneadm");
3002                         return (Z_ERR);
3003                 }
3004                 err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
3005                 if (err != Z_OK) {
3006                         errno = err;
3007                         zperror2(target_zone, gettext("could not set state"));
3008                         goto done;
3009                 }
3010 
3011                 if (!nodataset)
3012                         create_zfs_zonepath(zonepath);
3013         }
3014 
3015         status = do_subproc_interactive(cmdbuf);
3016         if ((subproc_err =
3017             subproc_status(gettext("brand-specific installation"), status,
3018             B_FALSE)) != ZONE_SUBPROC_OK) {
3019                 if (subproc_err == ZONE_SUBPROC_USAGE && !brand_help) {
3020                         sub_usage(SHELP_INSTALL, CMD_INSTALL);
3021                         zonecfg_release_lock_file(target_zone, lockfd);
3022                         return (Z_ERR);
3023                 }
3024                 err = Z_ERR;
3025                 goto done;
3026         }
3027 
3028         if (brand_help)
3029                 return (Z_OK);
3030 
3031         if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) {
3032                 errno = err;
3033                 zperror2(target_zone, gettext("could not set state"));
3034                 goto done;
3035         }
3036 
3037         if (do_postinstall) {
3038                 status = do_subproc(postcmdbuf);
3039 
3040                 if ((subproc_err =
3041                     subproc_status(gettext("brand-specific post-install"),
3042                     status, B_FALSE)) != ZONE_SUBPROC_OK) {
3043                         err = Z_ERR;
3044                         (void) zone_set_state(target_zone,
3045                             ZONE_STATE_INCOMPLETE);
3046                 }
3047         }
3048 
3049 done:
3050         /*
3051          * If the install script exited with ZONE_SUBPROC_NOTCOMPLETE, try to
3052          * clean up the zone and leave the zone in the CONFIGURED state so that
3053          * another install can be attempted without requiring an uninstall
3054          * first.
3055          */
3056         if (subproc_err == ZONE_SUBPROC_NOTCOMPLETE) {
3057                 if ((err = cleanup_zonepath(zonepath, B_FALSE)) != Z_OK) {
3058                         errno = err;
3059                         zperror2(target_zone,
3060                             gettext("cleaning up zonepath failed"));
3061                 } else if ((err = zone_set_state(target_zone,
3062                     ZONE_STATE_CONFIGURED)) != Z_OK) {
3063                         errno = err;
3064                         zperror2(target_zone, gettext("could not set state"));
3065                 }
3066         }
3067 
3068         if (!brand_help)
3069                 zonecfg_release_lock_file(target_zone, lockfd);
3070         return ((err == Z_OK) ? Z_OK : Z_ERR);
3071 }
3072 
3073 /*
3074  * Check that the inherited pkg dirs are the same for the clone and its source.
3075  * The easiest way to do that is check that the list of ipds is the same
3076  * by matching each one against the other.  This algorithm should be fine since
3077  * the list of ipds should not be that long.
3078  */
3079 static int
3080 valid_ipd_clone(zone_dochandle_t s_handle, char *source_zone,
3081         zone_dochandle_t t_handle, char *target_zone)
3082 {
3083         int err;
3084         int res = Z_OK;
3085         int s_cnt = 0;
3086         int t_cnt = 0;
3087         struct zone_fstab s_fstab;
3088         struct zone_fstab t_fstab;
3089 
3090         /*
3091          * First check the source of the clone against the target.
3092          */
3093         if ((err = zonecfg_setipdent(s_handle)) != Z_OK) {
3094                 errno = err;
3095                 zperror2(source_zone, gettext("could not enumerate "
3096                     "inherit-pkg-dirs"));
3097                 return (Z_ERR);
3098         }
3099 
3100         while (zonecfg_getipdent(s_handle, &s_fstab) == Z_OK) {
3101                 boolean_t match = B_FALSE;
3102 
3103                 s_cnt++;
3104 
3105                 if ((err = zonecfg_setipdent(t_handle)) != Z_OK) {
3106                         errno = err;
3107                         zperror2(target_zone, gettext("could not enumerate "
3108                             "inherit-pkg-dirs"));
3109                         (void) zonecfg_endipdent(s_handle);
3110                         return (Z_ERR);
3111                 }
3112 
3113                 while (zonecfg_getipdent(t_handle, &t_fstab) == Z_OK) {
3114                         if (strcmp(s_fstab.zone_fs_dir, t_fstab.zone_fs_dir)
3115                             == 0) {
3116                                 match = B_TRUE;
3117                                 break;
3118                         }
3119                 }
3120                 (void) zonecfg_endipdent(t_handle);
3121 
3122                 if (!match) {
3123                         (void) fprintf(stderr, gettext("inherit-pkg-dir "
3124                             "'%s' is not configured in zone %s.\n"),
3125                             s_fstab.zone_fs_dir, target_zone);
3126                         res = Z_ERR;
3127                 }
3128         }
3129 
3130         (void) zonecfg_endipdent(s_handle);
3131 
3132         /* skip the next check if we already have errors */
3133         if (res == Z_ERR)
3134                 return (res);
3135 
3136         /*
3137          * Now check the number of ipds in the target so we can verify
3138          * that the source is not a subset of the target.
3139          */
3140         if ((err = zonecfg_setipdent(t_handle)) != Z_OK) {
3141                 errno = err;
3142                 zperror2(target_zone, gettext("could not enumerate "
3143                     "inherit-pkg-dirs"));
3144                 return (Z_ERR);
3145         }
3146 
3147         while (zonecfg_getipdent(t_handle, &t_fstab) == Z_OK)
3148                 t_cnt++;
3149 
3150         (void) zonecfg_endipdent(t_handle);
3151 
3152         if (t_cnt != s_cnt) {
3153                 (void) fprintf(stderr, gettext("Zone %s is configured "
3154                     "with inherit-pkg-dirs that are not configured in zone "
3155                     "%s.\n"), target_zone, source_zone);
3156                 res = Z_ERR;
3157         }
3158 
3159         return (res);
3160 }
3161 
3162 static void
3163 warn_dev_match(zone_dochandle_t s_handle, char *source_zone,
3164         zone_dochandle_t t_handle, char *target_zone)
3165 {
3166         int err;
3167         struct zone_devtab s_devtab;
3168         struct zone_devtab t_devtab;
3169 
3170         if ((err = zonecfg_setdevent(t_handle)) != Z_OK) {
3171                 errno = err;
3172                 zperror2(target_zone, gettext("could not enumerate devices"));
3173                 return;
3174         }
3175 
3176         while (zonecfg_getdevent(t_handle, &t_devtab) == Z_OK) {
3177                 if ((err = zonecfg_setdevent(s_handle)) != Z_OK) {
3178                         errno = err;
3179                         zperror2(source_zone,
3180                             gettext("could not enumerate devices"));
3181                         (void) zonecfg_enddevent(t_handle);
3182                         return;
3183                 }
3184 
3185                 while (zonecfg_getdevent(s_handle, &s_devtab) == Z_OK) {
3186                         /*
3187                          * Use fnmatch to catch the case where wildcards
3188                          * were used in one zone and the other has an
3189                          * explicit entry (e.g. /dev/dsk/c0t0d0s6 vs.
3190                          * /dev/\*dsk/c0t0d0s6).
3191                          */
3192                         if (fnmatch(t_devtab.zone_dev_match,
3193                             s_devtab.zone_dev_match, FNM_PATHNAME) == 0 ||
3194                             fnmatch(s_devtab.zone_dev_match,
3195                             t_devtab.zone_dev_match, FNM_PATHNAME) == 0) {
3196                                 (void) fprintf(stderr,
3197                                     gettext("WARNING: device '%s' "
3198                                     "is configured in both zones.\n"),
3199                                     t_devtab.zone_dev_match);
3200                                 break;
3201                         }
3202                 }
3203                 (void) zonecfg_enddevent(s_handle);
3204         }
3205 
3206         (void) zonecfg_enddevent(t_handle);
3207 }
3208 
3209 /*
3210  * Check if the specified mount option (opt) is contained within the
3211  * options string.
3212  */
3213 static boolean_t
3214 opt_match(char *opt, char *options)
3215 {
3216         char *p;
3217         char *lastp;
3218 
3219         if ((p = strtok_r(options, ",", &lastp)) != NULL) {
3220                 if (strcmp(p, opt) == 0)
3221                         return (B_TRUE);
3222                 while ((p = strtok_r(NULL, ",", &lastp)) != NULL) {
3223                         if (strcmp(p, opt) == 0)
3224                                 return (B_TRUE);
3225                 }
3226         }
3227 
3228         return (B_FALSE);
3229 }
3230 
3231 #define RW_LOFS "WARNING: read-write lofs file system on '%s' is configured " \
3232         "in both zones.\n"
3233 
3234 static void
3235 print_fs_warnings(struct zone_fstab *s_fstab, struct zone_fstab *t_fstab)
3236 {
3237         /*
3238          * It is ok to have shared lofs mounted fs but we want to warn if
3239          * either is rw since this will effect the other zone.
3240          */
3241         if (strcmp(t_fstab->zone_fs_type, "lofs") == 0) {
3242                 zone_fsopt_t *optp;
3243 
3244                 /* The default is rw so no options means rw */
3245                 if (t_fstab->zone_fs_options == NULL ||
3246                     s_fstab->zone_fs_options == NULL) {
3247                         (void) fprintf(stderr, gettext(RW_LOFS),
3248                             t_fstab->zone_fs_special);
3249                         return;
3250                 }
3251 
3252                 for (optp = s_fstab->zone_fs_options; optp != NULL;
3253                     optp = optp->zone_fsopt_next) {
3254                         if (opt_match("rw", optp->zone_fsopt_opt)) {
3255                                 (void) fprintf(stderr, gettext(RW_LOFS),
3256                                     s_fstab->zone_fs_special);
3257                                 return;
3258                         }
3259                 }
3260 
3261                 for (optp = t_fstab->zone_fs_options; optp != NULL;
3262                     optp = optp->zone_fsopt_next) {
3263                         if (opt_match("rw", optp->zone_fsopt_opt)) {
3264                                 (void) fprintf(stderr, gettext(RW_LOFS),
3265                                     t_fstab->zone_fs_special);
3266                                 return;
3267                         }
3268                 }
3269 
3270                 return;
3271         }
3272 
3273         /*
3274          * TRANSLATION_NOTE
3275          * The first variable is the file system type and the second is
3276          * the file system special device.  For example,
3277          * WARNING: ufs file system on '/dev/dsk/c0t0d0s0' ...
3278          */
3279         (void) fprintf(stderr, gettext("WARNING: %s file system on '%s' "
3280             "is configured in both zones.\n"), t_fstab->zone_fs_type,
3281             t_fstab->zone_fs_special);
3282 }
3283 
3284 static void
3285 warn_fs_match(zone_dochandle_t s_handle, char *source_zone,
3286         zone_dochandle_t t_handle, char *target_zone)
3287 {
3288         int err;
3289         struct zone_fstab s_fstab;
3290         struct zone_fstab t_fstab;
3291 
3292         if ((err = zonecfg_setfsent(t_handle)) != Z_OK) {
3293                 errno = err;
3294                 zperror2(target_zone,
3295                     gettext("could not enumerate file systems"));
3296                 return;
3297         }
3298 
3299         while (zonecfg_getfsent(t_handle, &t_fstab) == Z_OK) {
3300                 if ((err = zonecfg_setfsent(s_handle)) != Z_OK) {
3301                         errno = err;
3302                         zperror2(source_zone,
3303                             gettext("could not enumerate file systems"));
3304                         (void) zonecfg_endfsent(t_handle);
3305                         return;
3306                 }
3307 
3308                 while (zonecfg_getfsent(s_handle, &s_fstab) == Z_OK) {
3309                         if (strcmp(t_fstab.zone_fs_special,
3310                             s_fstab.zone_fs_special) == 0) {
3311                                 print_fs_warnings(&s_fstab, &t_fstab);
3312                                 break;
3313                         }
3314                 }
3315                 (void) zonecfg_endfsent(s_handle);
3316         }
3317 
3318         (void) zonecfg_endfsent(t_handle);
3319 }
3320 
3321 /*
3322  * We don't catch the case where you used the same IP address but
3323  * it is not an exact string match.  For example, 192.9.0.128 vs. 192.09.0.128.
3324  * However, we're not going to worry about that but we will check for
3325  * a possible netmask on one of the addresses (e.g. 10.0.0.1 and 10.0.0.1/24)
3326  * and handle that case as a match.
3327  */
3328 static void
3329 warn_ip_match(zone_dochandle_t s_handle, char *source_zone,
3330         zone_dochandle_t t_handle, char *target_zone)
3331 {
3332         int err;
3333         struct zone_nwiftab s_nwiftab;
3334         struct zone_nwiftab t_nwiftab;
3335 
3336         if ((err = zonecfg_setnwifent(t_handle)) != Z_OK) {
3337                 errno = err;
3338                 zperror2(target_zone,
3339                     gettext("could not enumerate network interfaces"));
3340                 return;
3341         }
3342 
3343         while (zonecfg_getnwifent(t_handle, &t_nwiftab) == Z_OK) {
3344                 char *p;
3345 
3346                 /* remove an (optional) netmask from the address */
3347                 if ((p = strchr(t_nwiftab.zone_nwif_address, '/')) != NULL)
3348                         *p = '\0';
3349 
3350                 if ((err = zonecfg_setnwifent(s_handle)) != Z_OK) {
3351                         errno = err;
3352                         zperror2(source_zone,
3353                             gettext("could not enumerate network interfaces"));
3354                         (void) zonecfg_endnwifent(t_handle);
3355                         return;
3356                 }
3357 
3358                 while (zonecfg_getnwifent(s_handle, &s_nwiftab) == Z_OK) {
3359                         /* remove an (optional) netmask from the address */
3360                         if ((p = strchr(s_nwiftab.zone_nwif_address, '/'))
3361                             != NULL)
3362                                 *p = '\0';
3363 
3364                         /* For exclusive-IP zones, address is not specified. */
3365                         if (strlen(s_nwiftab.zone_nwif_address) == 0)
3366                                 continue;
3367 
3368                         if (strcmp(t_nwiftab.zone_nwif_address,
3369                             s_nwiftab.zone_nwif_address) == 0) {
3370                                 (void) fprintf(stderr,
3371                                     gettext("WARNING: network address '%s' "
3372                                     "is configured in both zones.\n"),
3373                                     t_nwiftab.zone_nwif_address);
3374                                 break;
3375                         }
3376                 }
3377                 (void) zonecfg_endnwifent(s_handle);
3378         }
3379 
3380         (void) zonecfg_endnwifent(t_handle);
3381 }
3382 
3383 static void
3384 warn_dataset_match(zone_dochandle_t s_handle, char *source,
3385         zone_dochandle_t t_handle, char *target)
3386 {
3387         int err;
3388         struct zone_dstab s_dstab;
3389         struct zone_dstab t_dstab;
3390 
3391         if ((err = zonecfg_setdsent(t_handle)) != Z_OK) {
3392                 errno = err;
3393                 zperror2(target, gettext("could not enumerate datasets"));
3394                 return;
3395         }
3396 
3397         while (zonecfg_getdsent(t_handle, &t_dstab) == Z_OK) {
3398                 if ((err = zonecfg_setdsent(s_handle)) != Z_OK) {
3399                         errno = err;
3400                         zperror2(source,
3401                             gettext("could not enumerate datasets"));
3402                         (void) zonecfg_enddsent(t_handle);
3403                         return;
3404                 }
3405 
3406                 while (zonecfg_getdsent(s_handle, &s_dstab) == Z_OK) {
3407                         if (strcmp(t_dstab.zone_dataset_name,
3408                             s_dstab.zone_dataset_name) == 0) {
3409                                 target_zone = source;
3410                                 zerror(gettext("WARNING: dataset '%s' "
3411                                     "is configured in both zones.\n"),
3412                                     t_dstab.zone_dataset_name);
3413                                 break;
3414                         }
3415                 }
3416                 (void) zonecfg_enddsent(s_handle);
3417         }
3418 
3419         (void) zonecfg_enddsent(t_handle);
3420 }
3421 
3422 /*
3423  * Check that the clone and its source have the same brand type.
3424  */
3425 static int
3426 valid_brand_clone(char *source_zone, char *target_zone)
3427 {
3428         brand_handle_t bh;
3429         char source_brand[MAXNAMELEN];
3430 
3431         if ((zone_get_brand(source_zone, source_brand,
3432             sizeof (source_brand))) != Z_OK) {
3433                 (void) fprintf(stderr, "%s: zone '%s': %s\n",
3434                     execname, source_zone, gettext("missing or invalid brand"));
3435                 return (Z_ERR);
3436         }
3437 
3438         if (strcmp(source_brand, target_brand) != NULL) {
3439                 (void) fprintf(stderr,
3440                     gettext("%s: Zones '%s' and '%s' have different brand "
3441                     "types.\n"), execname, source_zone, target_zone);
3442                 return (Z_ERR);
3443         }
3444 
3445         if ((bh = brand_open(target_brand)) == NULL) {
3446                 zerror(gettext("missing or invalid brand"));
3447                 return (Z_ERR);
3448         }
3449         brand_close(bh);
3450         return (Z_OK);
3451 }
3452 
3453 static int
3454 validate_clone(char *source_zone, char *target_zone)
3455 {
3456         int err = Z_OK;
3457         zone_dochandle_t s_handle;
3458         zone_dochandle_t t_handle;
3459 
3460         if ((t_handle = zonecfg_init_handle()) == NULL) {
3461                 zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3462                 return (Z_ERR);
3463         }
3464         if ((err = zonecfg_get_handle(target_zone, t_handle)) != Z_OK) {
3465                 errno = err;
3466                 zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3467                 zonecfg_fini_handle(t_handle);
3468                 return (Z_ERR);
3469         }
3470 
3471         if ((s_handle = zonecfg_init_handle()) == NULL) {
3472                 zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3473                 zonecfg_fini_handle(t_handle);
3474                 return (Z_ERR);
3475         }
3476         if ((err = zonecfg_get_handle(source_zone, s_handle)) != Z_OK) {
3477                 errno = err;
3478                 zperror(cmd_to_str(CMD_CLONE), B_TRUE);
3479                 goto done;
3480         }
3481 
3482         /* verify new zone has same brand type */
3483         err = valid_brand_clone(source_zone, target_zone);
3484         if (err != Z_OK)
3485                 goto done;
3486 
3487         /* verify new zone has same inherit-pkg-dirs */
3488         err = valid_ipd_clone(s_handle, source_zone, t_handle, target_zone);
3489 
3490         /* warn about imported fs's which are the same */
3491         warn_fs_match(s_handle, source_zone, t_handle, target_zone);
3492 
3493         /* warn about imported IP addresses which are the same */
3494         warn_ip_match(s_handle, source_zone, t_handle, target_zone);
3495 
3496         /* warn about imported devices which are the same */
3497         warn_dev_match(s_handle, source_zone, t_handle, target_zone);
3498 
3499         /* warn about imported datasets which are the same */
3500         warn_dataset_match(s_handle, source_zone, t_handle, target_zone);
3501 
3502 done:
3503         zonecfg_fini_handle(t_handle);
3504         zonecfg_fini_handle(s_handle);
3505 
3506         return ((err == Z_OK) ? Z_OK : Z_ERR);
3507 }
3508 
3509 static int
3510 copy_zone(char *src, char *dst)
3511 {
3512         boolean_t out_null = B_FALSE;
3513         int status;
3514         char *outfile;
3515         char cmdbuf[MAXPATHLEN * 2 + 128];
3516 
3517         if ((outfile = tempnam("/var/log", "zone")) == NULL) {
3518                 outfile = "/dev/null";
3519                 out_null = B_TRUE;
3520         }
3521 
3522         /*
3523          * Use find to get the list of files to copy.  We need to skip
3524          * files of type "socket" since cpio can't handle those but that
3525          * should be ok since the app will recreate the socket when it runs.
3526          * We also need to filter out anything under the .zfs subdir.  Since
3527          * find is running depth-first, we need the extra egrep to filter .zfs.
3528          */
3529         (void) snprintf(cmdbuf, sizeof (cmdbuf),
3530             "cd %s && /usr/bin/find . -type s -prune -o -depth -print | "
3531             "/usr/bin/egrep -v '^\\./\\.zfs$|^\\./\\.zfs/' | "
3532             "/usr/bin/cpio -pdmuP@ %s > %s 2>&1",
3533             src, dst, outfile);
3534 
3535         status = do_subproc(cmdbuf);
3536 
3537         if (subproc_status("copy", status, B_TRUE) != ZONE_SUBPROC_OK) {
3538                 if (!out_null)
3539                         (void) fprintf(stderr, gettext("\nThe copy failed.\n"
3540                             "More information can be found in %s\n"), outfile);
3541                 return (Z_ERR);
3542         }
3543 
3544         if (!out_null)
3545                 (void) unlink(outfile);
3546 
3547         return (Z_OK);
3548 }
3549 
3550 /* ARGSUSED */
3551 static int
3552 zfm_print(const char *p, void *r) {
3553         zerror("  %s\n", p);
3554         return (0);
3555 }
3556 
3557 int
3558 clone_copy(char *source_zonepath, char *zonepath)
3559 {
3560         int err;
3561 
3562         /* Don't clone the zone if anything is still mounted there */
3563         if (zonecfg_find_mounts(source_zonepath, NULL, NULL)) {
3564                 zerror(gettext("These file systems are mounted on "
3565                     "subdirectories of %s.\n"), source_zonepath);
3566                 (void) zonecfg_find_mounts(source_zonepath, zfm_print, NULL);
3567                 return (Z_ERR);
3568         }
3569 
3570         /*
3571          * Attempt to create a ZFS fs for the zonepath.  As usual, we don't
3572          * care if this works or not since we always have the default behavior
3573          * of a simple directory for the zonepath.
3574          */
3575         create_zfs_zonepath(zonepath);
3576 
3577         (void) printf(gettext("Copying %s..."), source_zonepath);
3578         (void) fflush(stdout);
3579 
3580         err = copy_zone(source_zonepath, zonepath);
3581 
3582         (void) printf("\n");
3583 
3584         return (err);
3585 }
3586 
3587 static int
3588 clone_func(int argc, char *argv[])
3589 {
3590         char *source_zone = NULL;
3591         int lockfd;
3592         int err, arg;
3593         char zonepath[MAXPATHLEN];
3594         char source_zonepath[MAXPATHLEN];
3595         zone_state_t state;
3596         zone_entry_t *zent;
3597         char *method = NULL;
3598         char *snapshot = NULL;
3599         char cmdbuf[MAXPATHLEN];
3600         char postcmdbuf[MAXPATHLEN];
3601         char presnapbuf[MAXPATHLEN];
3602         char postsnapbuf[MAXPATHLEN];
3603         char validsnapbuf[MAXPATHLEN];
3604         brand_handle_t bh = NULL;
3605         int status;
3606         boolean_t brand_help = B_FALSE;
3607 
3608         if (zonecfg_in_alt_root()) {
3609                 zerror(gettext("cannot clone zone in alternate root"));
3610                 return (Z_ERR);
3611         }
3612 
3613         /* Check the argv string for args we handle internally */
3614         optind = 0;
3615         opterr = 0;
3616         while ((arg = getopt(argc, argv, "?m:s:")) != EOF) {
3617                 switch (arg) {
3618                 case '?':
3619                         if (optopt == '?') {
3620                                 sub_usage(SHELP_CLONE, CMD_CLONE);
3621                                 brand_help = B_TRUE;
3622                         }
3623                         /* Ignore unknown options - may be brand specific. */
3624                         break;
3625                 case 'm':
3626                         method = optarg;
3627                         break;
3628                 case 's':
3629                         snapshot = optarg;
3630                         break;
3631                 default:
3632                         /* Ignore unknown options - may be brand specific. */
3633                         break;
3634                 }
3635         }
3636 
3637         if (argc != (optind + 1)) {
3638                 sub_usage(SHELP_CLONE, CMD_CLONE);
3639                 return (Z_USAGE);
3640         }
3641 
3642         source_zone = argv[optind];
3643 
3644         if (!brand_help) {
3645                 if (sanity_check(target_zone, CMD_CLONE, B_FALSE, B_TRUE,
3646                     B_FALSE) != Z_OK)
3647                         return (Z_ERR);
3648                 if (verify_details(CMD_CLONE, argv) != Z_OK)
3649                         return (Z_ERR);
3650 
3651                 /*
3652                  * We also need to do some extra validation on the source zone.
3653                  */
3654                 if (strcmp(source_zone, GLOBAL_ZONENAME) == 0) {
3655                         zerror(gettext("%s operation is invalid for the "
3656                             "global zone."), cmd_to_str(CMD_CLONE));
3657                         return (Z_ERR);
3658                 }
3659 
3660                 if (strncmp(source_zone, "SUNW", 4) == 0) {
3661                         zerror(gettext("%s operation is invalid for zones "
3662                             "starting with SUNW."), cmd_to_str(CMD_CLONE));
3663                         return (Z_ERR);
3664                 }
3665 
3666                 zent = lookup_running_zone(source_zone);
3667                 if (zent != NULL) {
3668                         /* check whether the zone is ready or running */
3669                         if ((err = zone_get_state(zent->zname,
3670                             &zent->zstate_num)) != Z_OK) {
3671                                 errno = err;
3672                                 zperror2(zent->zname, gettext("could not get "
3673                                     "state"));
3674                                 /* can't tell, so hedge */
3675                                 zent->zstate_str = "ready/running";
3676                         } else {
3677                                 zent->zstate_str =
3678                                     zone_state_str(zent->zstate_num);
3679                         }
3680                         zerror(gettext("%s operation is invalid for %s zones."),
3681                             cmd_to_str(CMD_CLONE), zent->zstate_str);
3682                         return (Z_ERR);
3683                 }
3684 
3685                 if ((err = zone_get_state(source_zone, &state)) != Z_OK) {
3686                         errno = err;
3687                         zperror2(source_zone, gettext("could not get state"));
3688                         return (Z_ERR);
3689                 }
3690                 if (state != ZONE_STATE_INSTALLED) {
3691                         (void) fprintf(stderr,
3692                             gettext("%s: zone %s is %s; %s is required.\n"),
3693                             execname, source_zone, zone_state_str(state),
3694                             zone_state_str(ZONE_STATE_INSTALLED));
3695                         return (Z_ERR);
3696                 }
3697 
3698                 /*
3699                  * The source zone checks out ok, continue with the clone.
3700                  */
3701 
3702                 if (validate_clone(source_zone, target_zone) != Z_OK)
3703                         return (Z_ERR);
3704 
3705                 if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) {
3706                         zerror(gettext("another %s may have an operation in "
3707                             "progress."), "zoneadm");
3708                         return (Z_ERR);
3709                 }
3710         }
3711 
3712         if ((err = zone_get_zonepath(source_zone, source_zonepath,
3713             sizeof (source_zonepath))) != Z_OK) {
3714                 errno = err;
3715                 zperror2(source_zone, gettext("could not get zone path"));
3716                 goto done;
3717         }
3718 
3719         if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath)))
3720             != Z_OK) {
3721                 errno = err;
3722                 zperror2(target_zone, gettext("could not get zone path"));
3723                 goto done;
3724         }
3725 
3726         /*
3727          * Fetch the clone and postclone hooks from the brand configuration.
3728          */
3729         if ((bh = brand_open(target_brand)) == NULL) {
3730                 zerror(gettext("missing or invalid brand"));
3731                 err = Z_ERR;
3732                 goto done;
3733         }
3734 
3735         if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_clone, target_zone,
3736             zonepath) != Z_OK) {
3737                 zerror("invalid brand configuration: missing clone resource");
3738                 brand_close(bh);
3739                 err = Z_ERR;
3740                 goto done;
3741         }
3742 
3743         if (get_hook(bh, postcmdbuf, sizeof (postcmdbuf), brand_get_postclone,
3744             target_zone, zonepath) != Z_OK) {
3745                 zerror("invalid brand configuration: missing postclone "
3746                     "resource");
3747                 brand_close(bh);
3748                 err = Z_ERR;
3749                 goto done;
3750         }
3751 
3752         if (get_hook(bh, presnapbuf, sizeof (presnapbuf), brand_get_presnap,
3753             source_zone, source_zonepath) != Z_OK) {
3754                 zerror("invalid brand configuration: missing presnap "
3755                     "resource");
3756                 brand_close(bh);
3757                 err = Z_ERR;
3758                 goto done;
3759         }
3760 
3761         if (get_hook(bh, postsnapbuf, sizeof (postsnapbuf), brand_get_postsnap,
3762             source_zone, source_zonepath) != Z_OK) {
3763                 zerror("invalid brand configuration: missing postsnap "
3764                     "resource");
3765                 brand_close(bh);
3766                 err = Z_ERR;
3767                 goto done;
3768         }
3769 
3770         if (get_hook(bh, validsnapbuf, sizeof (validsnapbuf),
3771             brand_get_validatesnap, target_zone, zonepath) != Z_OK) {
3772                 zerror("invalid brand configuration: missing validatesnap "
3773                     "resource");
3774                 brand_close(bh);
3775                 err = Z_ERR;
3776                 goto done;
3777         }
3778         brand_close(bh);
3779 
3780         /* Append all options to clone hook. */
3781         if (addoptions(cmdbuf, argv, sizeof (cmdbuf)) != Z_OK) {
3782                 err = Z_ERR;
3783                 goto done;
3784         }
3785 
3786         /* Append all options to postclone hook. */
3787         if (addoptions(postcmdbuf, argv, sizeof (postcmdbuf)) != Z_OK) {
3788                 err = Z_ERR;
3789                 goto done;
3790         }
3791 
3792         if (!brand_help) {
3793                 if ((err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE))
3794                     != Z_OK) {
3795                         errno = err;
3796                         zperror2(target_zone, gettext("could not set state"));
3797                         goto done;
3798                 }
3799         }
3800 
3801         /*
3802          * The clone hook is optional.  If it exists, use the hook for
3803          * cloning, otherwise use the built-in clone support
3804          */
3805         if (cmdbuf[0] != '\0') {
3806                 /* Run the clone hook */
3807                 status = do_subproc_interactive(cmdbuf);
3808                 if ((status = subproc_status(gettext("brand-specific clone"),
3809                     status, B_FALSE)) != ZONE_SUBPROC_OK) {
3810                         if (status == ZONE_SUBPROC_USAGE && !brand_help)
3811                                 sub_usage(SHELP_CLONE, CMD_CLONE);
3812                         err = Z_ERR;
3813                         goto done;
3814                 }
3815 
3816                 if (brand_help)
3817                         return (Z_OK);
3818 
3819         } else {
3820                 /* If just help, we're done since there is no brand help. */
3821                 if (brand_help)
3822                         return (Z_OK);
3823 
3824                 /* Run the built-in clone support. */
3825 
3826                 /* The only explicit built-in method is "copy". */
3827                 if (method != NULL && strcmp(method, "copy") != 0) {
3828                         sub_usage(SHELP_CLONE, CMD_CLONE);
3829                         err = Z_USAGE;
3830                         goto done;
3831                 }
3832 
3833                 if (snapshot != NULL) {
3834                         err = clone_snapshot_zfs(snapshot, zonepath,
3835                             validsnapbuf);
3836                 } else {
3837                         /*
3838                          * We always copy the clone unless the source is ZFS
3839                          * and a ZFS clone worked.  We fallback to copying if
3840                          * the ZFS clone fails for some reason.
3841                          */
3842                         err = Z_ERR;
3843                         if (method == NULL && is_zonepath_zfs(source_zonepath))
3844                                 err = clone_zfs(source_zonepath, zonepath,
3845                                     presnapbuf, postsnapbuf);
3846 
3847                         if (err != Z_OK)
3848                                 err = clone_copy(source_zonepath, zonepath);
3849                 }
3850         }
3851 
3852         if (err == Z_OK && postcmdbuf[0] != '\0') {
3853                 status = do_subproc(postcmdbuf);
3854                 if ((err = subproc_status("postclone", status, B_FALSE))
3855                     != ZONE_SUBPROC_OK) {
3856                         zerror(gettext("post-clone configuration failed."));
3857                         err = Z_ERR;
3858                 }
3859         }
3860 
3861 done:
3862         /*
3863          * If everything went well, we mark the zone as installed.
3864          */
3865         if (err == Z_OK) {
3866                 err = zone_set_state(target_zone, ZONE_STATE_INSTALLED);
3867                 if (err != Z_OK) {
3868                         errno = err;
3869                         zperror2(target_zone, gettext("could not set state"));
3870                 }
3871         }
3872         if (!brand_help)
3873                 zonecfg_release_lock_file(target_zone, lockfd);
3874         return ((err == Z_OK) ? Z_OK : Z_ERR);
3875 }
3876 
3877 /*
3878  * Used when removing a zonepath after uninstalling or cleaning up after
3879  * the move subcommand.  This handles a zonepath that has non-standard
3880  * contents so that we will only cleanup the stuff we know about and leave
3881  * any user data alone.
3882  *
3883  * If the "all" parameter is true then we should remove the whole zonepath
3884  * even if it has non-standard files/directories in it.  This can be used when
3885  * we need to cleanup after moving the zonepath across file systems.
3886  *
3887  * We "exec" the RMCOMMAND so that the returned status is that of RMCOMMAND
3888  * and not the shell.
3889  */
3890 static int
3891 cleanup_zonepath(char *zonepath, boolean_t all)
3892 {
3893         int             status;
3894         int             i;
3895         boolean_t       non_std = B_FALSE;
3896         struct dirent   *dp;
3897         DIR             *dirp;
3898                         /*
3899                          * The SUNWattached.xml file is expected since it might
3900                          * exist if the zone was force-attached after a
3901                          * migration.
3902                          */
3903         char            *std_entries[] = {"dev", "lu", "root",
3904                             "SUNWattached.xml", NULL};
3905                         /* (MAXPATHLEN * 3) is for the 3 std_entries dirs */
3906         char            cmdbuf[sizeof (RMCOMMAND) + (MAXPATHLEN * 3) + 64];
3907 
3908         /*
3909          * We shouldn't need these checks but lets be paranoid since we
3910          * could blow away the whole system here if we got the wrong zonepath.
3911          */
3912         if (*zonepath == NULL || strcmp(zonepath, "/") == 0) {
3913                 (void) fprintf(stderr, "invalid zonepath '%s'\n", zonepath);
3914                 return (Z_INVAL);
3915         }
3916 
3917         /*
3918          * If the dirpath is already gone (maybe it was manually removed) then
3919          * we just return Z_OK so that the cleanup is successful.
3920          */
3921         if ((dirp = opendir(zonepath)) == NULL)
3922                 return (Z_OK);
3923 
3924         /*
3925          * Look through the zonepath directory to see if there are any
3926          * non-standard files/dirs.  Also skip .zfs since that might be
3927          * there but we'll handle ZFS file systems as a special case.
3928          */
3929         while ((dp = readdir(dirp)) != NULL) {
3930                 if (strcmp(dp->d_name, ".") == 0 ||
3931                     strcmp(dp->d_name, "..") == 0 ||
3932                     strcmp(dp->d_name, ".zfs") == 0)
3933                         continue;
3934 
3935                 for (i = 0; std_entries[i] != NULL; i++)
3936                         if (strcmp(dp->d_name, std_entries[i]) == 0)
3937                                 break;
3938 
3939                 if (std_entries[i] == NULL)
3940                         non_std = B_TRUE;
3941         }
3942         (void) closedir(dirp);
3943 
3944         if (!all && non_std) {
3945                 /*
3946                  * There are extra, non-standard directories/files in the
3947                  * zonepath so we don't want to remove the zonepath.  We
3948                  * just want to remove the standard directories and leave
3949                  * the user data alone.
3950                  */
3951                 (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND);
3952 
3953                 for (i = 0; std_entries[i] != NULL; i++) {
3954                         char tmpbuf[MAXPATHLEN];
3955 
3956                         if (snprintf(tmpbuf, sizeof (tmpbuf), " %s/%s",
3957                             zonepath, std_entries[i]) >= sizeof (tmpbuf) ||
3958                             strlcat(cmdbuf, tmpbuf, sizeof (cmdbuf)) >=
3959                             sizeof (cmdbuf)) {
3960                                 (void) fprintf(stderr,
3961                                     gettext("path is too long\n"));
3962                                 return (Z_INVAL);
3963                         }
3964                 }
3965 
3966                 status = do_subproc(cmdbuf);
3967 
3968                 (void) fprintf(stderr, gettext("WARNING: Unable to completely "
3969                     "remove %s\nbecause it contains additional user data.  "
3970                     "Only the standard directory\nentries have been "
3971                     "removed.\n"),
3972                     zonepath);
3973 
3974                 return ((subproc_status(RMCOMMAND, status, B_TRUE) ==
3975                     ZONE_SUBPROC_OK) ? Z_OK : Z_ERR);
3976         }
3977 
3978         /*
3979          * There is nothing unexpected in the zonepath, try to get rid of the
3980          * whole zonepath directory.
3981          *
3982          * If the zonepath is its own zfs file system, try to destroy the
3983          * file system.  If that fails for some reason (e.g. it has clones)
3984          * then we'll just remove the contents of the zonepath.
3985          */
3986         if (is_zonepath_zfs(zonepath)) {
3987                 if (destroy_zfs(zonepath) == Z_OK)
3988                         return (Z_OK);
3989                 (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND
3990                     " %s/*", zonepath);
3991                 status = do_subproc(cmdbuf);
3992                 return ((subproc_status(RMCOMMAND, status, B_TRUE) ==
3993                     ZONE_SUBPROC_OK) ? Z_OK : Z_ERR);
3994         }
3995 
3996         (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s",
3997             zonepath);
3998         status = do_subproc(cmdbuf);
3999 
4000         return ((subproc_status(RMCOMMAND, status, B_TRUE) == ZONE_SUBPROC_OK)
4001             ? Z_OK : Z_ERR);
4002 }
4003 
4004 static int
4005 move_func(int argc, char *argv[])
4006 {
4007         char *new_zonepath = NULL;
4008         int lockfd;
4009         int err, arg;
4010         char zonepath[MAXPATHLEN];
4011         zone_dochandle_t handle;
4012         boolean_t fast;
4013         boolean_t is_zfs = B_FALSE;
4014         struct dirent *dp;
4015         DIR *dirp;
4016         boolean_t empty = B_TRUE;
4017         boolean_t revert;
4018         struct stat zonepath_buf;
4019         struct stat new_zonepath_buf;
4020 
4021         if (zonecfg_in_alt_root()) {
4022                 zerror(gettext("cannot move zone in alternate root"));
4023                 return (Z_ERR);
4024         }
4025 
4026         optind = 0;
4027         if ((arg = getopt(argc, argv, "?")) != EOF) {
4028                 switch (arg) {
4029                 case '?':
4030                         sub_usage(SHELP_MOVE, CMD_MOVE);
4031                         return (optopt == '?' ? Z_OK : Z_USAGE);
4032                 default:
4033                         sub_usage(SHELP_MOVE, CMD_MOVE);
4034                         return (Z_USAGE);
4035                 }
4036         }
4037         if (argc != (optind + 1)) {
4038                 sub_usage(SHELP_MOVE, CMD_MOVE);
4039                 return (Z_USAGE);
4040         }
4041         new_zonepath = argv[optind];
4042         if (sanity_check(target_zone, CMD_MOVE, B_FALSE, B_TRUE, B_FALSE)
4043             != Z_OK)
4044                 return (Z_ERR);
4045         if (verify_details(CMD_MOVE, argv) != Z_OK)
4046                 return (Z_ERR);
4047 
4048         /*
4049          * Check out the new zonepath.  This has the side effect of creating
4050          * a directory for the new zonepath.  We depend on this later when we
4051          * stat to see if we are doing a cross file system move or not.
4052          */
4053         if (validate_zonepath(new_zonepath, CMD_MOVE) != Z_OK)
4054                 return (Z_ERR);
4055 
4056         if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath)))
4057             != Z_OK) {
4058                 errno = err;
4059                 zperror2(target_zone, gettext("could not get zone path"));
4060                 return (Z_ERR);
4061         }
4062 
4063         if (stat(zonepath, &zonepath_buf) == -1) {
4064                 zperror(gettext("could not stat zone path"), B_FALSE);
4065                 return (Z_ERR);
4066         }
4067 
4068         if (stat(new_zonepath, &new_zonepath_buf) == -1) {
4069                 zperror(gettext("could not stat new zone path"), B_FALSE);
4070                 return (Z_ERR);
4071         }
4072 
4073         /*
4074          * Check if the destination directory is empty.
4075          */
4076         if ((dirp = opendir(new_zonepath)) == NULL) {
4077                 zperror(gettext("could not open new zone path"), B_FALSE);
4078                 return (Z_ERR);
4079         }
4080         while ((dp = readdir(dirp)) != (struct dirent *)0) {
4081                 if (strcmp(dp->d_name, ".") == 0 ||
4082                     strcmp(dp->d_name, "..") == 0)
4083                         continue;
4084                 empty = B_FALSE;
4085                 break;
4086         }
4087         (void) closedir(dirp);
4088 
4089         /* Error if there is anything in the destination directory. */
4090         if (!empty) {
4091                 (void) fprintf(stderr, gettext("could not move zone to %s: "
4092                     "directory not empty\n"), new_zonepath);
4093                 return (Z_ERR);
4094         }
4095 
4096         /* Don't move the zone if anything is still mounted there */
4097         if (zonecfg_find_mounts(zonepath, NULL, NULL)) {
4098                 zerror(gettext("These file systems are mounted on "
4099                     "subdirectories of %s.\n"), zonepath);
4100                 (void) zonecfg_find_mounts(zonepath, zfm_print, NULL);
4101                 return (Z_ERR);
4102         }
4103 
4104         /*
4105          * Check if we are moving in the same file system and can do a fast
4106          * move or if we are crossing file systems and have to copy the data.
4107          */
4108         fast = (zonepath_buf.st_dev == new_zonepath_buf.st_dev);
4109 
4110         if ((handle = zonecfg_init_handle()) == NULL) {
4111                 zperror(cmd_to_str(CMD_MOVE), B_TRUE);
4112                 return (Z_ERR);
4113         }
4114 
4115         if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
4116                 errno = err;
4117                 zperror(cmd_to_str(CMD_MOVE), B_TRUE);
4118                 zonecfg_fini_handle(handle);
4119                 return (Z_ERR);
4120         }
4121 
4122         if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) {
4123                 zerror(gettext("another %s may have an operation in progress."),
4124                     "zoneadm");
4125                 zonecfg_fini_handle(handle);
4126                 return (Z_ERR);
4127         }
4128 
4129         /*
4130          * We're making some file system changes now so we have to clean up
4131          * the file system before we are done.  This will either clean up the
4132          * new zonepath if the zonecfg update failed or it will clean up the
4133          * old zonepath if everything is ok.
4134          */
4135         revert = B_TRUE;
4136 
4137         if (is_zonepath_zfs(zonepath) &&
4138             move_zfs(zonepath, new_zonepath) != Z_ERR) {
4139                 is_zfs = B_TRUE;
4140 
4141         } else if (fast) {
4142                 /* same file system, use rename for a quick move */
4143 
4144                 /*
4145                  * Remove the new_zonepath directory that got created above
4146                  * during the validation.  It gets in the way of the rename.
4147                  */
4148                 if (rmdir(new_zonepath) != 0) {
4149                         zperror(gettext("could not rmdir new zone path"),
4150                             B_FALSE);
4151                         zonecfg_fini_handle(handle);
4152                         zonecfg_release_lock_file(target_zone, lockfd);
4153                         return (Z_ERR);
4154                 }
4155 
4156                 if (rename(zonepath, new_zonepath) != 0) {
4157                         /*
4158                          * If this fails we don't need to do all of the
4159                          * cleanup that happens for the rest of the code
4160                          * so just return from this error.
4161                          */
4162                         zperror(gettext("could not move zone"), B_FALSE);
4163                         zonecfg_fini_handle(handle);
4164                         zonecfg_release_lock_file(target_zone, lockfd);
4165                         return (Z_ERR);
4166                 }
4167 
4168         } else {
4169                 /*
4170                  * Attempt to create a ZFS fs for the new zonepath.  As usual,
4171                  * we don't care if this works or not since we always have the
4172                  * default behavior of a simple directory for the zonepath.
4173                  */
4174                 create_zfs_zonepath(new_zonepath);
4175 
4176                 (void) printf(gettext(
4177                     "Moving across file systems; copying zonepath %s..."),
4178                     zonepath);
4179                 (void) fflush(stdout);
4180 
4181                 err = copy_zone(zonepath, new_zonepath);
4182 
4183                 (void) printf("\n");
4184                 if (err != Z_OK)
4185                         goto done;
4186         }
4187 
4188         if ((err = zonecfg_set_zonepath(handle, new_zonepath)) != Z_OK) {
4189                 errno = err;
4190                 zperror(gettext("could not set new zonepath"), B_TRUE);
4191                 goto done;
4192         }
4193 
4194         if ((err = zonecfg_save(handle)) != Z_OK) {
4195                 errno = err;
4196                 zperror(gettext("zonecfg save failed"), B_TRUE);
4197                 goto done;
4198         }
4199 
4200         revert = B_FALSE;
4201 
4202 done:
4203         zonecfg_fini_handle(handle);
4204         zonecfg_release_lock_file(target_zone, lockfd);
4205 
4206         /*
4207          * Clean up the file system based on how things went.  We either
4208          * clean up the new zonepath if the operation failed for some reason
4209          * or we clean up the old zonepath if everything is ok.
4210          */
4211         if (revert) {
4212                 /* The zonecfg update failed, cleanup the new zonepath. */
4213                 if (is_zfs) {
4214                         if (move_zfs(new_zonepath, zonepath) == Z_ERR) {
4215                                 (void) fprintf(stderr, gettext("could not "
4216                                     "restore zonepath, the zfs mountpoint is "
4217                                     "set as:\n%s\n"), new_zonepath);
4218                                 /*
4219                                  * err is already != Z_OK since we're reverting
4220                                  */
4221                         }
4222 
4223                 } else if (fast) {
4224                         if (rename(new_zonepath, zonepath) != 0) {
4225                                 zperror(gettext("could not restore zonepath"),
4226                                     B_FALSE);
4227                                 /*
4228                                  * err is already != Z_OK since we're reverting
4229                                  */
4230                         }
4231                 } else {
4232                         (void) printf(gettext("Cleaning up zonepath %s..."),
4233                             new_zonepath);
4234                         (void) fflush(stdout);
4235                         err = cleanup_zonepath(new_zonepath, B_TRUE);
4236                         (void) printf("\n");
4237 
4238                         if (err != Z_OK) {
4239                                 errno = err;
4240                                 zperror(gettext("could not remove new "
4241                                     "zonepath"), B_TRUE);
4242                         } else {
4243                                 /*
4244                                  * Because we're reverting we know the mainline
4245                                  * code failed but we just reused the err
4246                                  * variable so we reset it back to Z_ERR.
4247                                  */
4248                                 err = Z_ERR;
4249                         }
4250                 }
4251 
4252         } else {
4253                 /* The move was successful, cleanup the old zonepath. */
4254                 if (!is_zfs && !fast) {
4255                         (void) printf(
4256                             gettext("Cleaning up zonepath %s..."), zonepath);
4257                         (void) fflush(stdout);
4258                         err = cleanup_zonepath(zonepath, B_TRUE);
4259                         (void) printf("\n");
4260 
4261                         if (err != Z_OK) {
4262                                 errno = err;
4263                                 zperror(gettext("could not remove zonepath"),
4264                                     B_TRUE);
4265                         }
4266                 }
4267         }
4268 
4269         return ((err == Z_OK) ? Z_OK : Z_ERR);
4270 }
4271 
4272 /* ARGSUSED */
4273 static int
4274 detach_func(int argc, char *argv[])
4275 {
4276         int lockfd = -1;
4277         int err, arg;
4278         char zonepath[MAXPATHLEN];
4279         char cmdbuf[MAXPATHLEN];
4280         char precmdbuf[MAXPATHLEN];
4281         boolean_t execute = B_TRUE;
4282         boolean_t brand_help = B_FALSE;
4283         brand_handle_t bh = NULL;
4284         int status;
4285 
4286         if (zonecfg_in_alt_root()) {
4287                 zerror(gettext("cannot detach zone in alternate root"));
4288                 return (Z_ERR);
4289         }
4290 
4291         /* Check the argv string for args we handle internally */
4292         optind = 0;
4293         opterr = 0;
4294         while ((arg = getopt(argc, argv, "?n")) != EOF) {
4295                 switch (arg) {
4296                 case '?':
4297                         if (optopt == '?') {
4298                                 sub_usage(SHELP_DETACH, CMD_DETACH);
4299                                 brand_help = B_TRUE;
4300                         }
4301                         /* Ignore unknown options - may be brand specific. */
4302                         break;
4303                 case 'n':
4304                         execute = B_FALSE;
4305                         break;
4306                 default:
4307                         /* Ignore unknown options - may be brand specific. */
4308                         break;
4309                 }
4310         }
4311 
4312         if (brand_help)
4313                 execute = B_FALSE;
4314 
4315         if (execute) {
4316                 if (sanity_check(target_zone, CMD_DETACH, B_FALSE, B_TRUE,
4317                     B_FALSE) != Z_OK)
4318                         return (Z_ERR);
4319                 if (verify_details(CMD_DETACH, argv) != Z_OK)
4320                         return (Z_ERR);
4321         } else {
4322                 /*
4323                  * We want a dry-run to work for a non-privileged user so we
4324                  * only do minimal validation.
4325                  */
4326                 if (target_zone == NULL) {
4327                         zerror(gettext("no zone specified"));
4328                         return (Z_ERR);
4329                 }
4330 
4331                 if (strcmp(target_zone, GLOBAL_ZONENAME) == 0) {
4332                         zerror(gettext("%s operation is invalid for the "
4333                             "global zone."), cmd_to_str(CMD_DETACH));
4334                         return (Z_ERR);
4335                 }
4336         }
4337 
4338         if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath)))
4339             != Z_OK) {
4340                 errno = err;
4341                 zperror2(target_zone, gettext("could not get zone path"));
4342                 return (Z_ERR);
4343         }
4344 
4345         /* Fetch the detach and predetach hooks from the brand configuration. */
4346         if ((bh = brand_open(target_brand)) == NULL) {
4347                 zerror(gettext("missing or invalid brand"));
4348                 return (Z_ERR);
4349         }
4350 
4351         if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_detach, target_zone,
4352             zonepath) != Z_OK) {
4353                 zerror("invalid brand configuration: missing detach resource");
4354                 brand_close(bh);
4355                 return (Z_ERR);
4356         }
4357 
4358         if (get_hook(bh, precmdbuf, sizeof (precmdbuf), brand_get_predetach,
4359             target_zone, zonepath) != Z_OK) {
4360                 zerror("invalid brand configuration: missing predetach "
4361                     "resource");
4362                 brand_close(bh);
4363                 return (Z_ERR);
4364         }
4365         brand_close(bh);
4366 
4367         /* Append all options to predetach hook. */
4368         if (addoptions(precmdbuf, argv, sizeof (precmdbuf)) != Z_OK)
4369                 return (Z_ERR);
4370 
4371         /* Append all options to detach hook. */
4372         if (addoptions(cmdbuf, argv, sizeof (cmdbuf)) != Z_OK)
4373                 return (Z_ERR);
4374 
4375         if (execute && zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) {
4376                 zerror(gettext("another %s may have an operation in progress."),
4377                     "zoneadm");
4378                 return (Z_ERR);
4379         }
4380 
4381         /* If we have a brand predetach hook, run it. */
4382         if (!brand_help && precmdbuf[0] != '\0') {
4383                 status = do_subproc(precmdbuf);
4384                 if (subproc_status(gettext("brand-specific predetach"),
4385                     status, B_FALSE) != ZONE_SUBPROC_OK) {
4386 
4387                         if (execute) {
4388                                 assert(lockfd >= 0);
4389                                 zonecfg_release_lock_file(target_zone, lockfd);
4390                                 lockfd = -1;
4391                         }
4392 
4393                         assert(lockfd == -1);
4394                         return (Z_ERR);
4395                 }
4396         }
4397 
4398         if (cmdbuf[0] != '\0') {
4399                 /* Run the detach hook */
4400                 status = do_subproc_interactive(cmdbuf);
4401                 if ((status = subproc_status(gettext("brand-specific detach"),
4402                     status, B_FALSE)) != ZONE_SUBPROC_OK) {
4403                         if (status == ZONE_SUBPROC_USAGE && !brand_help)
4404                                 sub_usage(SHELP_DETACH, CMD_DETACH);
4405 
4406                         if (execute) {
4407                                 assert(lockfd >= 0);
4408                                 zonecfg_release_lock_file(target_zone, lockfd);
4409                                 lockfd = -1;
4410                         }
4411 
4412                         assert(lockfd == -1);
4413                         return (Z_ERR);
4414                 }
4415 
4416         } else {
4417                 zone_dochandle_t handle;
4418 
4419                 /* If just help, we're done since there is no brand help. */
4420                 if (brand_help) {
4421                         assert(lockfd == -1);
4422                         return (Z_OK);
4423                 }
4424 
4425                 /*
4426                  * Run the built-in detach support.  Just generate a simple
4427                  * zone definition XML file and detach.
4428                  */
4429 
4430                 /* Don't detach the zone if anything is still mounted there */
4431                 if (execute && zonecfg_find_mounts(zonepath, NULL, NULL)) {
4432                         (void) fprintf(stderr, gettext("These file systems are "
4433                             "mounted on subdirectories of %s.\n"), zonepath);
4434                         (void) zonecfg_find_mounts(zonepath, zfm_print, NULL);
4435                         err = ZONE_SUBPROC_NOTCOMPLETE;
4436                         goto done;
4437                 }
4438 
4439                 if ((handle = zonecfg_init_handle()) == NULL) {
4440                         zperror(cmd_to_str(CMD_DETACH), B_TRUE);
4441                         err = ZONE_SUBPROC_NOTCOMPLETE;
4442                         goto done;
4443                 }
4444 
4445                 if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
4446                         errno = err;
4447                         zperror(cmd_to_str(CMD_DETACH), B_TRUE);
4448 
4449                 } else if ((err = zonecfg_detach_save(handle,
4450                     (execute ? 0 : ZONE_DRY_RUN))) != Z_OK) {
4451                         errno = err;
4452                         zperror(gettext("saving the detach manifest failed"),
4453                             B_TRUE);
4454                 }
4455 
4456                 zonecfg_fini_handle(handle);
4457                 if (err != Z_OK)
4458                         goto done;
4459         }
4460 
4461         /*
4462          * Set the zone state back to configured unless we are running with the
4463          * no-execute option.
4464          */
4465         if (execute && (err = zone_set_state(target_zone,
4466             ZONE_STATE_CONFIGURED)) != Z_OK) {
4467                 errno = err;
4468                 zperror(gettext("could not reset state"), B_TRUE);
4469         }
4470 
4471 done:
4472         if (execute) {
4473                 assert(lockfd >= 0);
4474                 zonecfg_release_lock_file(target_zone, lockfd);
4475                 lockfd = -1;
4476         }
4477 
4478         assert(lockfd == -1);
4479         return ((err == Z_OK) ? Z_OK : Z_ERR);
4480 }
4481 
4482 /*
4483  * Determine the brand when doing a dry-run attach.  The zone does not have to
4484  * exist, so we have to read the incoming manifest to determine the zone's
4485  * brand.
4486  *
4487  * Because the manifest has to be processed twice; once to determine the brand
4488  * and once to do the brand-specific attach logic, we always read it into a tmp
4489  * file.  This handles the manifest coming from stdin or a regular file.  The
4490  * tmpname parameter returns the name of the temporary file that the manifest
4491  * was read into.
4492  */
4493 static int
4494 dryrun_get_brand(char *manifest_path, char *tmpname, int size)
4495 {
4496         int fd;
4497         int err;
4498         int res = Z_OK;
4499         zone_dochandle_t local_handle;
4500         zone_dochandle_t rem_handle = NULL;
4501         int len;
4502         int ofd;
4503         char buf[512];
4504 
4505         if (strcmp(manifest_path, "-") == 0) {
4506                 fd = STDIN_FILENO;
4507         } else {
4508                 if ((fd = open(manifest_path, O_RDONLY)) < 0) {
4509                         if (getcwd(buf, sizeof (buf)) == NULL)
4510                                 (void) strlcpy(buf, "/", sizeof (buf));
4511                         zerror(gettext("could not open manifest path %s%s: %s"),
4512                             (*manifest_path == '/' ? "" : buf), manifest_path,
4513                             strerror(errno));
4514                         return (Z_ERR);
4515                 }
4516         }
4517 
4518         (void) snprintf(tmpname, size, "/var/run/zone.%d", getpid());
4519 
4520         if ((ofd = open(tmpname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
4521                 zperror(gettext("could not save manifest"), B_FALSE);
4522                 (void) close(fd);
4523                 return (Z_ERR);
4524         }
4525 
4526         while ((len = read(fd, buf, sizeof (buf))) > 0) {
4527                 if (write(ofd, buf, len) == -1) {
4528                         zperror(gettext("could not save manifest"), B_FALSE);
4529                         (void) close(ofd);
4530                         (void) close(fd);
4531                         return (Z_ERR);
4532                 }
4533         }
4534 
4535         if (close(ofd) != 0) {
4536                 zperror(gettext("could not save manifest"), B_FALSE);
4537                 (void) close(fd);
4538                 return (Z_ERR);
4539         }
4540 
4541         (void) close(fd);
4542 
4543         if ((fd = open(tmpname, O_RDONLY)) < 0) {
4544                 zperror(gettext("could not open manifest path"), B_FALSE);
4545                 return (Z_ERR);
4546         }
4547 
4548         if ((local_handle = zonecfg_init_handle()) == NULL) {
4549                 zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
4550                 res = Z_ERR;
4551                 goto done;
4552         }
4553 
4554         if ((rem_handle = zonecfg_init_handle()) == NULL) {
4555                 zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
4556                 res = Z_ERR;
4557                 goto done;
4558         }
4559 
4560         if ((err = zonecfg_attach_manifest(fd, local_handle, rem_handle))
4561             != Z_OK) {
4562                 res = Z_ERR;
4563 
4564                 if (err == Z_INVALID_DOCUMENT) {
4565                         struct stat st;
4566                         char buf[6];
4567 
4568                         if (strcmp(manifest_path, "-") == 0) {
4569                                 zerror(gettext("Input is not a valid XML "
4570                                     "file"));
4571                                 goto done;
4572                         }
4573 
4574                         if (fstat(fd, &st) == -1 || !S_ISREG(st.st_mode)) {
4575                                 zerror(gettext("%s is not an XML file"),
4576                                     manifest_path);
4577                                 goto done;
4578                         }
4579 
4580                         bzero(buf, sizeof (buf));
4581                         (void) lseek(fd, 0L, SEEK_SET);
4582                         if (read(fd, buf, sizeof (buf) - 1) < 0 ||
4583                             strncmp(buf, "<?xml", 5) != 0)
4584                                 zerror(gettext("%s is not an XML file"),
4585                                     manifest_path);
4586                         else
4587                                 zerror(gettext("Cannot attach to an earlier "
4588                                     "release of the operating system"));
4589                 } else {
4590                         zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
4591                 }
4592                 goto done;
4593         }
4594 
4595         /* Retrieve remote handle brand type. */
4596         if (zonecfg_get_brand(rem_handle, target_brand, sizeof (target_brand))
4597             != Z_OK) {
4598                 zerror(gettext("missing or invalid brand"));
4599                 exit(Z_ERR);
4600         }
4601 
4602 done:
4603         zonecfg_fini_handle(local_handle);
4604         zonecfg_fini_handle(rem_handle);
4605         (void) close(fd);
4606 
4607         return ((res == Z_OK) ? Z_OK : Z_ERR);
4608 }
4609 
4610 /* ARGSUSED */
4611 static int
4612 attach_func(int argc, char *argv[])
4613 {
4614         int lockfd = -1;
4615         int err, arg;
4616         boolean_t force = B_FALSE;
4617         zone_dochandle_t handle;
4618         char zonepath[MAXPATHLEN];
4619         char cmdbuf[MAXPATHLEN];
4620         char postcmdbuf[MAXPATHLEN];
4621         boolean_t execute = B_TRUE;
4622         boolean_t brand_help = B_FALSE;
4623         char *manifest_path;
4624         char tmpmanifest[80];
4625         int manifest_pos;
4626         brand_handle_t bh = NULL;
4627         int status;
4628 
4629         if (zonecfg_in_alt_root()) {
4630                 zerror(gettext("cannot attach zone in alternate root"));
4631                 return (Z_ERR);
4632         }
4633 
4634         /* Check the argv string for args we handle internally */
4635         optind = 0;
4636         opterr = 0;
4637         while ((arg = getopt(argc, argv, "?Fn:")) != EOF) {
4638                 switch (arg) {
4639                 case '?':
4640                         if (optopt == '?') {
4641                                 sub_usage(SHELP_ATTACH, CMD_ATTACH);
4642                                 brand_help = B_TRUE;
4643                         }
4644                         /* Ignore unknown options - may be brand specific. */
4645                         break;
4646                 case 'F':
4647                         force = B_TRUE;
4648                         break;
4649                 case 'n':
4650                         execute = B_FALSE;
4651                         manifest_path = optarg;
4652                         manifest_pos = optind - 1;
4653                         break;
4654                 default:
4655                         /* Ignore unknown options - may be brand specific. */
4656                         break;
4657                 }
4658         }
4659 
4660         if (brand_help) {
4661                 force = B_FALSE;
4662                 execute = B_TRUE;
4663         }
4664 
4665         /* dry-run and force flags are mutually exclusive */
4666         if (!execute && force) {
4667                 zerror(gettext("-F and -n flags are mutually exclusive"));
4668                 return (Z_ERR);
4669         }
4670 
4671         /*
4672          * If the no-execute option was specified, we don't do validation and
4673          * need to figure out the brand, since there is no zone required to be
4674          * configured for this option.
4675          */
4676         if (execute) {
4677                 if (!brand_help) {
4678                         if (sanity_check(target_zone, CMD_ATTACH, B_FALSE,
4679                             B_TRUE, B_FALSE) != Z_OK)
4680                                 return (Z_ERR);
4681                         if (verify_details(CMD_ATTACH, argv) != Z_OK)
4682                                 return (Z_ERR);
4683                 }
4684 
4685                 if ((err = zone_get_zonepath(target_zone, zonepath,
4686                     sizeof (zonepath))) != Z_OK) {
4687                         errno = err;
4688                         zperror2(target_zone,
4689                             gettext("could not get zone path"));
4690                         return (Z_ERR);
4691                 }
4692         } else {
4693                 if (dryrun_get_brand(manifest_path, tmpmanifest,
4694                     sizeof (tmpmanifest)) != Z_OK)
4695                         return (Z_ERR);
4696 
4697                 argv[manifest_pos] = tmpmanifest;
4698                 target_zone = "-";
4699                 (void) strlcpy(zonepath, "-", sizeof (zonepath));
4700 
4701                 /* Run the brand's verify_adm hook. */
4702                 if (verify_brand(NULL, CMD_ATTACH, argv) != Z_OK)
4703                         return (Z_ERR);
4704         }
4705 
4706         /*
4707          * Fetch the attach and postattach hooks from the brand configuration.
4708          */
4709         if ((bh = brand_open(target_brand)) == NULL) {
4710                 zerror(gettext("missing or invalid brand"));
4711                 return (Z_ERR);
4712         }
4713 
4714         if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_attach, target_zone,
4715             zonepath) != Z_OK) {
4716                 zerror("invalid brand configuration: missing attach resource");
4717                 brand_close(bh);
4718                 return (Z_ERR);
4719         }
4720 
4721         if (get_hook(bh, postcmdbuf, sizeof (postcmdbuf), brand_get_postattach,
4722             target_zone, zonepath) != Z_OK) {
4723                 zerror("invalid brand configuration: missing postattach "
4724                     "resource");
4725                 brand_close(bh);
4726                 return (Z_ERR);
4727         }
4728         brand_close(bh);
4729 
4730         /* Append all options to attach hook. */
4731         if (addoptions(cmdbuf, argv, sizeof (cmdbuf)) != Z_OK)
4732                 return (Z_ERR);
4733 
4734         /* Append all options to postattach hook. */
4735         if (addoptions(postcmdbuf, argv, sizeof (postcmdbuf)) != Z_OK)
4736                 return (Z_ERR);
4737 
4738         if (execute && !brand_help) {
4739                 if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) {
4740                         zerror(gettext("another %s may have an operation in "
4741                             "progress."), "zoneadm");
4742                         return (Z_ERR);
4743                 }
4744         }
4745 
4746         if (!force) {
4747                 /*
4748                  * Not a force-attach, so we need to actually do the work.
4749                  */
4750                 if (cmdbuf[0] != '\0') {
4751                         /* Run the attach hook */
4752                         status = do_subproc_interactive(cmdbuf);
4753                         if ((status = subproc_status(gettext("brand-specific "
4754                             "attach"), status, B_FALSE)) != ZONE_SUBPROC_OK) {
4755                                 if (status == ZONE_SUBPROC_USAGE && !brand_help)
4756                                         sub_usage(SHELP_ATTACH, CMD_ATTACH);
4757 
4758                                 if (execute && !brand_help) {
4759                                         assert(lockfd >= 0);
4760                                         zonecfg_release_lock_file(target_zone,
4761                                             lockfd);
4762                                         lockfd = -1;
4763                                 }
4764 
4765                                 assert(lockfd == -1);
4766                                 return (Z_ERR);
4767                         }
4768                 }
4769 
4770                 /*
4771                  * Else run the built-in attach support.
4772                  * This is a no-op since there is nothing to validate.
4773                  */
4774 
4775                 /* If dry-run or help, then we're done. */
4776                 if (!execute || brand_help) {
4777                         if (!execute)
4778                                 (void) unlink(tmpmanifest);
4779                         assert(lockfd == -1);
4780                         return (Z_OK);
4781                 }
4782         }
4783 
4784         if ((handle = zonecfg_init_handle()) == NULL) {
4785                 zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
4786                 err = Z_ERR;
4787         } else if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
4788                 errno = err;
4789                 zperror(cmd_to_str(CMD_ATTACH), B_TRUE);
4790                 zonecfg_fini_handle(handle);
4791         } else {
4792                 zonecfg_rm_detached(handle, force);
4793                 zonecfg_fini_handle(handle);
4794         }
4795 
4796         if (err == Z_OK &&
4797             (err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) {
4798                 errno = err;
4799                 zperror(gettext("could not reset state"), B_TRUE);
4800         }
4801 
4802         assert(lockfd >= 0);
4803         zonecfg_release_lock_file(target_zone, lockfd);
4804         lockfd = -1;
4805 
4806         /* If we have a brand postattach hook, run it. */
4807         if (err == Z_OK && !force && postcmdbuf[0] != '\0') {
4808                 status = do_subproc(postcmdbuf);
4809                 if (subproc_status(gettext("brand-specific postattach"),
4810                     status, B_FALSE) != ZONE_SUBPROC_OK) {
4811                         if ((err = zone_set_state(target_zone,
4812                             ZONE_STATE_CONFIGURED)) != Z_OK) {
4813                                 errno = err;
4814                                 zperror(gettext("could not reset state"),
4815                                     B_TRUE);
4816                         }
4817                 }
4818         }
4819 
4820         assert(lockfd == -1);
4821         return ((err == Z_OK) ? Z_OK : Z_ERR);
4822 }
4823 
4824 /*
4825  * On input, TRUE => yes, FALSE => no.
4826  * On return, TRUE => 1, FALSE => 0, could not ask => -1.
4827  */
4828 
4829 static int
4830 ask_yesno(boolean_t default_answer, const char *question)
4831 {
4832         char line[64];  /* should be large enough to answer yes or no */
4833 
4834         if (!isatty(STDIN_FILENO))
4835                 return (-1);
4836         for (;;) {
4837                 (void) printf("%s (%s)? ", question,
4838                     default_answer ? "[y]/n" : "y/[n]");
4839                 if (fgets(line, sizeof (line), stdin) == NULL ||
4840                     line[0] == '\n')
4841                         return (default_answer ? 1 : 0);
4842                 if (tolower(line[0]) == 'y')
4843                         return (1);
4844                 if (tolower(line[0]) == 'n')
4845                         return (0);
4846         }
4847 }
4848 
4849 /* ARGSUSED */
4850 static int
4851 uninstall_func(int argc, char *argv[])
4852 {
4853         char line[ZONENAME_MAX + 128];  /* Enough for "Are you sure ..." */
4854         char rootpath[MAXPATHLEN], zonepath[MAXPATHLEN];
4855         char cmdbuf[MAXPATHLEN];
4856         char precmdbuf[MAXPATHLEN];
4857         boolean_t force = B_FALSE;
4858         int lockfd, answer;
4859         int err, arg;
4860         boolean_t brand_help = B_FALSE;
4861         brand_handle_t bh = NULL;
4862         int status;
4863 
4864         if (zonecfg_in_alt_root()) {
4865                 zerror(gettext("cannot uninstall zone in alternate root"));
4866                 return (Z_ERR);
4867         }
4868 
4869         /* Check the argv string for args we handle internally */
4870         optind = 0;
4871         opterr = 0;
4872         while ((arg = getopt(argc, argv, "?F")) != EOF) {
4873                 switch (arg) {
4874                 case '?':
4875                         if (optopt == '?') {
4876                                 sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL);
4877                                 brand_help = B_TRUE;
4878                         }
4879                         /* Ignore unknown options - may be brand specific. */
4880                         break;
4881                 case 'F':
4882                         force = B_TRUE;
4883                         break;
4884                 default:
4885                         /* Ignore unknown options - may be brand specific. */
4886                         break;
4887                 }
4888         }
4889 
4890         if (!brand_help) {
4891                 if (sanity_check(target_zone, CMD_UNINSTALL, B_FALSE, B_TRUE,
4892                     B_FALSE) != Z_OK)
4893                         return (Z_ERR);
4894 
4895                 /*
4896                  * Invoke brand-specific handler.
4897                  */
4898                 if (invoke_brand_handler(CMD_UNINSTALL, argv) != Z_OK)
4899                         return (Z_ERR);
4900 
4901                 if (!force) {
4902                         (void) snprintf(line, sizeof (line),
4903                             gettext("Are you sure you want to %s zone %s"),
4904                             cmd_to_str(CMD_UNINSTALL), target_zone);
4905                         if ((answer = ask_yesno(B_FALSE, line)) == 0) {
4906                                 return (Z_OK);
4907                         } else if (answer == -1) {
4908                                 zerror(gettext("Input not from terminal and -F "
4909                                     "not specified: %s not done."),
4910                                     cmd_to_str(CMD_UNINSTALL));
4911                                 return (Z_ERR);
4912                         }
4913                 }
4914         }
4915 
4916         if ((err = zone_get_zonepath(target_zone, zonepath,
4917             sizeof (zonepath))) != Z_OK) {
4918                 errno = err;
4919                 zperror2(target_zone, gettext("could not get zone path"));
4920                 return (Z_ERR);
4921         }
4922 
4923         /*
4924          * Fetch the uninstall and preuninstall hooks from the brand
4925          * configuration.
4926          */
4927         if ((bh = brand_open(target_brand)) == NULL) {
4928                 zerror(gettext("missing or invalid brand"));
4929                 return (Z_ERR);
4930         }
4931 
4932         if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_uninstall,
4933             target_zone, zonepath) != Z_OK) {
4934                 zerror("invalid brand configuration: missing uninstall "
4935                     "resource");
4936                 brand_close(bh);
4937                 return (Z_ERR);
4938         }
4939 
4940         if (get_hook(bh, precmdbuf, sizeof (precmdbuf), brand_get_preuninstall,
4941             target_zone, zonepath) != Z_OK) {
4942                 zerror("invalid brand configuration: missing preuninstall "
4943                     "resource");
4944                 brand_close(bh);
4945                 return (Z_ERR);
4946         }
4947         brand_close(bh);
4948 
4949         /* Append all options to preuninstall hook. */
4950         if (addoptions(precmdbuf, argv, sizeof (precmdbuf)) != Z_OK)
4951                 return (Z_ERR);
4952 
4953         /* Append all options to uninstall hook. */
4954         if (addoptions(cmdbuf, argv, sizeof (cmdbuf)) != Z_OK)
4955                 return (Z_ERR);
4956 
4957         if (!brand_help) {
4958                 if ((err = zone_get_rootpath(target_zone, rootpath,
4959                     sizeof (rootpath))) != Z_OK) {
4960                         errno = err;
4961                         zperror2(target_zone, gettext("could not get root "
4962                             "path"));
4963                         return (Z_ERR);
4964                 }
4965 
4966                 /*
4967                  * If there seems to be a zoneadmd running for this zone, call
4968                  * it to tell it that an uninstall is happening; if all goes
4969                  * well it will then shut itself down.
4970                  */
4971                 if (zonecfg_ping_zoneadmd(target_zone) == Z_OK) {
4972                         zone_cmd_arg_t zarg;
4973                         zarg.cmd = Z_NOTE_UNINSTALLING;
4974                         /* we don't care too much if this fails, just plow on */
4975                         (void) zonecfg_call_zoneadmd(target_zone, &zarg, locale,
4976                             B_TRUE);
4977                 }
4978 
4979                 if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) {
4980                         zerror(gettext("another %s may have an operation in "
4981                             "progress."), "zoneadm");
4982                         return (Z_ERR);
4983                 }
4984 
4985                 /* Don't uninstall the zone if anything is mounted there */
4986                 err = zonecfg_find_mounts(rootpath, NULL, NULL);
4987                 if (err) {
4988                         zerror(gettext("These file systems are mounted on "
4989                             "subdirectories of %s.\n"), rootpath);
4990                         (void) zonecfg_find_mounts(rootpath, zfm_print, NULL);
4991                         zonecfg_release_lock_file(target_zone, lockfd);
4992                         return (Z_ERR);
4993                 }
4994         }
4995 
4996         /* If we have a brand preuninstall hook, run it. */
4997         if (!brand_help && precmdbuf[0] != '\0') {
4998                 status = do_subproc(cmdbuf);
4999                 if (subproc_status(gettext("brand-specific preuninstall"),
5000                     status, B_FALSE) != ZONE_SUBPROC_OK) {
5001                         zonecfg_release_lock_file(target_zone, lockfd);
5002                         return (Z_ERR);
5003                 }
5004         }
5005 
5006         if (!brand_help) {
5007                 err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
5008                 if (err != Z_OK) {
5009                         errno = err;
5010                         zperror2(target_zone, gettext("could not set state"));
5011                         goto bad;
5012                 }
5013         }
5014 
5015         /*
5016          * If there is a brand uninstall hook, use it, otherwise use the
5017          * built-in uninstall code.
5018          */
5019         if (cmdbuf[0] != '\0') {
5020                 /* Run the uninstall hook */
5021                 status = do_subproc_interactive(cmdbuf);
5022                 if ((status = subproc_status(gettext("brand-specific "
5023                     "uninstall"), status, B_FALSE)) != ZONE_SUBPROC_OK) {
5024                         if (status == ZONE_SUBPROC_USAGE && !brand_help)
5025                                 sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL);
5026                         if (!brand_help)
5027                                 zonecfg_release_lock_file(target_zone, lockfd);
5028                         return (Z_ERR);
5029                 }
5030 
5031                 if (brand_help)
5032                         return (Z_OK);
5033         } else {
5034                 /* If just help, we're done since there is no brand help. */
5035                 if (brand_help)
5036                         return (Z_OK);
5037 
5038                 /* Run the built-in uninstall support. */
5039                 if ((err = cleanup_zonepath(zonepath, B_FALSE)) != Z_OK) {
5040                         errno = err;
5041                         zperror2(target_zone, gettext("cleaning up zonepath "
5042                             "failed"));
5043                         goto bad;
5044                 }
5045         }
5046 
5047         err = zone_set_state(target_zone, ZONE_STATE_CONFIGURED);
5048         if (err != Z_OK) {
5049                 errno = err;
5050                 zperror2(target_zone, gettext("could not reset state"));
5051         }
5052 bad:
5053         zonecfg_release_lock_file(target_zone, lockfd);
5054         return (err);
5055 }
5056 
5057 /* ARGSUSED */
5058 static int
5059 mount_func(int argc, char *argv[])
5060 {
5061         zone_cmd_arg_t zarg;
5062         boolean_t force = B_FALSE;
5063         int arg;
5064 
5065         /*
5066          * The only supported subargument to the "mount" subcommand is
5067          * "-f", which forces us to mount a zone in the INCOMPLETE state.
5068          */
5069         optind = 0;
5070         if ((arg = getopt(argc, argv, "f")) != EOF) {
5071                 switch (arg) {
5072                 case 'f':
5073                         force = B_TRUE;
5074                         break;
5075                 default:
5076                         return (Z_USAGE);
5077                 }
5078         }
5079         if (argc > optind)
5080                 return (Z_USAGE);
5081 
5082         if (sanity_check(target_zone, CMD_MOUNT, B_FALSE, B_FALSE, force)
5083             != Z_OK)
5084                 return (Z_ERR);
5085         if (verify_details(CMD_MOUNT, argv) != Z_OK)
5086                 return (Z_ERR);
5087 
5088         zarg.cmd = force ? Z_FORCEMOUNT : Z_MOUNT;
5089         zarg.bootbuf[0] = '\0';
5090         if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
5091                 zerror(gettext("call to %s failed"), "zoneadmd");
5092                 return (Z_ERR);
5093         }
5094         return (Z_OK);
5095 }
5096 
5097 /* ARGSUSED */
5098 static int
5099 unmount_func(int argc, char *argv[])
5100 {
5101         zone_cmd_arg_t zarg;
5102 
5103         if (argc > 0)
5104                 return (Z_USAGE);
5105         if (sanity_check(target_zone, CMD_UNMOUNT, B_FALSE, B_FALSE, B_FALSE)
5106             != Z_OK)
5107                 return (Z_ERR);
5108 
5109         zarg.cmd = Z_UNMOUNT;
5110         if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) {
5111                 zerror(gettext("call to %s failed"), "zoneadmd");
5112                 return (Z_ERR);
5113         }
5114         return (Z_OK);
5115 }
5116 
5117 static int
5118 mark_func(int argc, char *argv[])
5119 {
5120         int err, lockfd;
5121 
5122         if (argc != 1 || strcmp(argv[0], "incomplete") != 0)
5123                 return (Z_USAGE);
5124         if (sanity_check(target_zone, CMD_MARK, B_FALSE, B_FALSE, B_FALSE)
5125             != Z_OK)
5126                 return (Z_ERR);
5127 
5128         /*
5129          * Invoke brand-specific handler.
5130          */
5131         if (invoke_brand_handler(CMD_MARK, argv) != Z_OK)
5132                 return (Z_ERR);
5133 
5134         if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) {
5135                 zerror(gettext("another %s may have an operation in progress."),
5136                     "zoneadm");
5137                 return (Z_ERR);
5138         }
5139 
5140         err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE);
5141         if (err != Z_OK) {
5142                 errno = err;
5143                 zperror2(target_zone, gettext("could not set state"));
5144         }
5145         zonecfg_release_lock_file(target_zone, lockfd);
5146 
5147         return (err);
5148 }
5149 
5150 /*
5151  * Check what scheduling class we're running under and print a warning if
5152  * we're not using FSS.
5153  */
5154 static int
5155 check_sched_fss(zone_dochandle_t handle)
5156 {
5157         char class_name[PC_CLNMSZ];
5158 
5159         if (zonecfg_get_dflt_sched_class(handle, class_name,
5160             sizeof (class_name)) != Z_OK) {
5161                 zerror(gettext("WARNING: unable to determine the zone's "
5162                     "scheduling class"));
5163         } else if (strcmp("FSS", class_name) != 0) {
5164                 zerror(gettext("WARNING: The zone.cpu-shares rctl is set but\n"
5165                     "FSS is not the default scheduling class for this zone.  "
5166                     "FSS will be\nused for processes in the zone but to get "
5167                     "the full benefit of FSS,\nit should be the default "
5168                     "scheduling class.  See dispadmin(1M) for\nmore details."));
5169                 return (Z_SYSTEM);
5170         }
5171 
5172         return (Z_OK);
5173 }
5174 
5175 static int
5176 check_cpu_shares_sched(zone_dochandle_t handle)
5177 {
5178         int err;
5179         int res = Z_OK;
5180         struct zone_rctltab rctl;
5181 
5182         if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
5183                 errno = err;
5184                 zperror(cmd_to_str(CMD_APPLY), B_TRUE);
5185                 return (err);
5186         }
5187 
5188         while (zonecfg_getrctlent(handle, &rctl) == Z_OK) {
5189                 if (strcmp(rctl.zone_rctl_name, "zone.cpu-shares") == 0) {
5190                         if (check_sched_fss(handle) != Z_OK)
5191                                 res = Z_SYSTEM;
5192                         break;
5193                 }
5194         }
5195 
5196         (void) zonecfg_endrctlent(handle);
5197 
5198         return (res);
5199 }
5200 
5201 /*
5202  * Check if there is a mix of processes running in different pools within the
5203  * zone.  This is currently only going to be called for the global zone from
5204  * apply_func but that could be generalized in the future.
5205  */
5206 static boolean_t
5207 mixed_pools(zoneid_t zoneid)
5208 {
5209         DIR *dirp;
5210         dirent_t *dent;
5211         boolean_t mixed = B_FALSE;
5212         boolean_t poolid_set = B_FALSE;
5213         poolid_t last_poolid = 0;
5214 
5215         if ((dirp = opendir("/proc")) == NULL) {
5216                 zerror(gettext("could not open /proc"));
5217                 return (B_FALSE);
5218         }
5219 
5220         while ((dent = readdir(dirp)) != NULL) {
5221                 int procfd;
5222                 psinfo_t ps;
5223                 char procpath[MAXPATHLEN];
5224 
5225                 if (dent->d_name[0] == '.')
5226                         continue;
5227 
5228                 (void) snprintf(procpath, sizeof (procpath), "/proc/%s/psinfo",
5229                     dent->d_name);
5230 
5231                 if ((procfd = open(procpath, O_RDONLY)) == -1)
5232                         continue;
5233 
5234                 if (read(procfd, &ps, sizeof (ps)) == sizeof (psinfo_t)) {
5235                         /* skip processes in other zones and system processes */
5236                         if (zoneid != ps.pr_zoneid || ps.pr_flag & SSYS) {
5237                                 (void) close(procfd);
5238                                 continue;
5239                         }
5240 
5241                         if (poolid_set) {
5242                                 if (ps.pr_poolid != last_poolid)
5243                                         mixed = B_TRUE;
5244                         } else {
5245                                 last_poolid = ps.pr_poolid;
5246                                 poolid_set = B_TRUE;
5247                         }
5248                 }
5249 
5250                 (void) close(procfd);
5251 
5252                 if (mixed)
5253                         break;
5254         }
5255 
5256         (void) closedir(dirp);
5257 
5258         return (mixed);
5259 }
5260 
5261 /*
5262  * Check if a persistent or temporary pool is configured for the zone.
5263  * This is currently only going to be called for the global zone from
5264  * apply_func but that could be generalized in the future.
5265  */
5266 static boolean_t
5267 pool_configured(zone_dochandle_t handle)
5268 {
5269         int err1, err2;
5270         struct zone_psettab pset_tab;
5271         char poolname[MAXPATHLEN];
5272 
5273         err1 = zonecfg_lookup_pset(handle, &pset_tab);
5274         err2 = zonecfg_get_pool(handle, poolname, sizeof (poolname));
5275 
5276         if (err1 == Z_NO_ENTRY &&
5277             (err2 == Z_NO_ENTRY || (err2 == Z_OK && strlen(poolname) == 0)))
5278                 return (B_FALSE);
5279 
5280         return (B_TRUE);
5281 }
5282 
5283 /*
5284  * This is an undocumented interface which is currently only used to apply
5285  * the global zone resource management settings when the system boots.
5286  * This function does not yet properly handle updating a running system so
5287  * any projects running in the zone would be trashed if this function
5288  * were to run after the zone had booted.  It also does not reset any
5289  * rctl settings that were removed from zonecfg.  There is still work to be
5290  * done before we can properly support dynamically updating the resource
5291  * management settings for a running zone (global or non-global).  Thus, this
5292  * functionality is undocumented for now.
5293  */
5294 /* ARGSUSED */
5295 static int
5296 apply_func(int argc, char *argv[])
5297 {
5298         int err;
5299         int res = Z_OK;
5300         priv_set_t *privset;
5301         zoneid_t zoneid;
5302         zone_dochandle_t handle;
5303         struct zone_mcaptab mcap;
5304         char pool_err[128];
5305 
5306         zoneid = getzoneid();
5307 
5308         if (zonecfg_in_alt_root() || zoneid != GLOBAL_ZONEID ||
5309             target_zone == NULL || strcmp(target_zone, GLOBAL_ZONENAME) != 0)
5310                 return (usage(B_FALSE));
5311 
5312         if ((privset = priv_allocset()) == NULL) {
5313                 zerror(gettext("%s failed"), "priv_allocset");
5314                 return (Z_ERR);
5315         }
5316 
5317         if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
5318                 zerror(gettext("%s failed"), "getppriv");
5319                 priv_freeset(privset);
5320                 return (Z_ERR);
5321         }
5322 
5323         if (priv_isfullset(privset) == B_FALSE) {
5324                 (void) usage(B_FALSE);
5325                 priv_freeset(privset);
5326                 return (Z_ERR);
5327         }
5328         priv_freeset(privset);
5329 
5330         if ((handle = zonecfg_init_handle()) == NULL) {
5331                 zperror(cmd_to_str(CMD_APPLY), B_TRUE);
5332                 return (Z_ERR);
5333         }
5334 
5335         if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
5336                 errno = err;
5337                 zperror(cmd_to_str(CMD_APPLY), B_TRUE);
5338                 zonecfg_fini_handle(handle);
5339                 return (Z_ERR);
5340         }
5341 
5342         /* specific error msgs are printed within apply_rctls */
5343         if ((err = zonecfg_apply_rctls(target_zone, handle)) != Z_OK) {
5344                 errno = err;
5345                 zperror(cmd_to_str(CMD_APPLY), B_TRUE);
5346                 res = Z_ERR;
5347         }
5348 
5349         if ((err = check_cpu_shares_sched(handle)) != Z_OK)
5350                 res = Z_ERR;
5351 
5352         if (pool_configured(handle)) {
5353                 if (mixed_pools(zoneid)) {
5354                         zerror(gettext("Zone is using multiple resource "
5355                             "pools.  The pool\nconfiguration cannot be "
5356                             "applied without rebooting."));
5357                         res = Z_ERR;
5358                 } else {
5359 
5360                         /*
5361                          * The next two blocks of code attempt to set up
5362                          * temporary pools as well as persistent pools.  In
5363                          * both cases we call the functions unconditionally.
5364                          * Within each funtion the code will check if the zone
5365                          * is actually configured for a temporary pool or
5366                          * persistent pool and just return if there is nothing
5367                          * to do.
5368                          */
5369                         if ((err = zonecfg_bind_tmp_pool(handle, zoneid,
5370                             pool_err, sizeof (pool_err))) != Z_OK) {
5371                                 if (err == Z_POOL || err == Z_POOL_CREATE ||
5372                                     err == Z_POOL_BIND)
5373                                         zerror("%s: %s", zonecfg_strerror(err),
5374                                             pool_err);
5375                                 else
5376                                         zerror(gettext("could not bind zone to "
5377                                             "temporary pool: %s"),
5378                                             zonecfg_strerror(err));
5379                                 res = Z_ERR;
5380                         }
5381 
5382                         if ((err = zonecfg_bind_pool(handle, zoneid, pool_err,
5383                             sizeof (pool_err))) != Z_OK) {
5384                                 if (err == Z_POOL || err == Z_POOL_BIND)
5385                                         zerror("%s: %s", zonecfg_strerror(err),
5386                                             pool_err);
5387                                 else
5388                                         zerror("%s", zonecfg_strerror(err));
5389                         }
5390                 }
5391         }
5392 
5393         /*
5394          * If a memory cap is configured, set the cap in the kernel using
5395          * zone_setattr() and make sure the rcapd SMF service is enabled.
5396          */
5397         if (zonecfg_getmcapent(handle, &mcap) == Z_OK) {
5398                 uint64_t num;
5399                 char smf_err[128];
5400 
5401                 num = (uint64_t)strtoll(mcap.zone_physmem_cap, NULL, 10);
5402                 if (zone_setattr(zoneid, ZONE_ATTR_PHYS_MCAP, &num, 0) == -1) {
5403                         zerror(gettext("could not set zone memory cap"));
5404                         res = Z_ERR;
5405                 }
5406 
5407                 if (zonecfg_enable_rcapd(smf_err, sizeof (smf_err)) != Z_OK) {
5408                         zerror(gettext("enabling system/rcap service failed: "
5409                             "%s"), smf_err);
5410                         res = Z_ERR;
5411                 }
5412         }
5413 
5414         zonecfg_fini_handle(handle);
5415 
5416         return (res);
5417 }
5418 
5419 static int
5420 help_func(int argc, char *argv[])
5421 {
5422         int arg, cmd_num;
5423 
5424         if (argc == 0) {
5425                 (void) usage(B_TRUE);
5426                 return (Z_OK);
5427         }
5428         optind = 0;
5429         if ((arg = getopt(argc, argv, "?")) != EOF) {
5430                 switch (arg) {
5431                 case '?':
5432                         sub_usage(SHELP_HELP, CMD_HELP);
5433                         return (optopt == '?' ? Z_OK : Z_USAGE);
5434                 default:
5435                         sub_usage(SHELP_HELP, CMD_HELP);
5436                         return (Z_USAGE);
5437                 }
5438         }
5439         while (optind < argc) {
5440                 /* Private commands have NULL short_usage; omit them */
5441                 if ((cmd_num = cmd_match(argv[optind])) < 0 ||
5442                     cmdtab[cmd_num].short_usage == NULL) {
5443                         sub_usage(SHELP_HELP, CMD_HELP);
5444                         return (Z_USAGE);
5445                 }
5446                 sub_usage(cmdtab[cmd_num].short_usage, cmd_num);
5447                 optind++;
5448         }
5449         return (Z_OK);
5450 }
5451 
5452 /*
5453  * Returns: CMD_MIN thru CMD_MAX on success, -1 on error
5454  */
5455 
5456 static int
5457 cmd_match(char *cmd)
5458 {
5459         int i;
5460 
5461         for (i = CMD_MIN; i <= CMD_MAX; i++) {
5462                 /* return only if there is an exact match */
5463                 if (strcmp(cmd, cmdtab[i].cmd_name) == 0)
5464                         return (cmdtab[i].cmd_num);
5465         }
5466         return (-1);
5467 }
5468 
5469 static int
5470 parse_and_run(int argc, char *argv[])
5471 {
5472         int i = cmd_match(argv[0]);
5473 
5474         if (i < 0)
5475                 return (usage(B_FALSE));
5476         return (cmdtab[i].handler(argc - 1, &(argv[1])));
5477 }
5478 
5479 static char *
5480 get_execbasename(char *execfullname)
5481 {
5482         char *last_slash, *execbasename;
5483 
5484         /* guard against '/' at end of command invocation */
5485         for (;;) {
5486                 last_slash = strrchr(execfullname, '/');
5487                 if (last_slash == NULL) {
5488                         execbasename = execfullname;
5489                         break;
5490                 } else {
5491                         execbasename = last_slash + 1;
5492                         if (*execbasename == '\0') {
5493                                 *last_slash = '\0';
5494                                 continue;
5495                         }
5496                         break;
5497                 }
5498         }
5499         return (execbasename);
5500 }
5501 
5502 int
5503 main(int argc, char **argv)
5504 {
5505         int arg;
5506         zoneid_t zid;
5507         struct stat st;
5508         char *zone_lock_env;
5509         int err;
5510 
5511         if ((locale = setlocale(LC_ALL, "")) == NULL)
5512                 locale = "C";
5513         (void) textdomain(TEXT_DOMAIN);
5514         setbuf(stdout, NULL);
5515         (void) sigset(SIGHUP, SIG_IGN);
5516         execname = get_execbasename(argv[0]);
5517         target_zone = NULL;
5518         if (chdir("/") != 0) {
5519                 zerror(gettext("could not change directory to /."));
5520                 exit(Z_ERR);
5521         }
5522 
5523         if (init_zfs() != Z_OK)
5524                 exit(Z_ERR);
5525 
5526         while ((arg = getopt(argc, argv, "?u:z:R:")) != EOF) {
5527                 switch (arg) {
5528                 case '?':
5529                         return (usage(B_TRUE));
5530                 case 'u':
5531                         target_uuid = optarg;
5532                         break;
5533                 case 'z':
5534                         target_zone = optarg;
5535                         break;
5536                 case 'R':       /* private option for admin/install use */
5537                         if (*optarg != '/') {
5538                                 zerror(gettext("root path must be absolute."));
5539                                 exit(Z_ERR);
5540                         }
5541                         if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) {
5542                                 zerror(
5543                                     gettext("root path must be a directory."));
5544                                 exit(Z_ERR);
5545                         }
5546                         zonecfg_set_root(optarg);
5547                         break;
5548                 default:
5549                         return (usage(B_FALSE));
5550                 }
5551         }
5552 
5553         if (optind >= argc)
5554                 return (usage(B_FALSE));
5555 
5556         if (target_uuid != NULL && *target_uuid != '\0') {
5557                 uuid_t uuid;
5558                 static char newtarget[ZONENAME_MAX];
5559 
5560                 if (uuid_parse(target_uuid, uuid) == -1) {
5561                         zerror(gettext("illegal UUID value specified"));
5562                         exit(Z_ERR);
5563                 }
5564                 if (zonecfg_get_name_by_uuid(uuid, newtarget,
5565                     sizeof (newtarget)) == Z_OK)
5566                         target_zone = newtarget;
5567         }
5568 
5569         if (target_zone != NULL && zone_get_id(target_zone, &zid) != 0) {
5570                 errno = Z_NO_ZONE;
5571                 zperror(target_zone, B_TRUE);
5572                 exit(Z_ERR);
5573         }
5574 
5575         /*
5576          * See if we have inherited the right to manipulate this zone from
5577          * a zoneadm instance in our ancestry.  If so, set zone_lock_cnt to
5578          * indicate it.  If not, make that explicit in our environment.
5579          */
5580         zonecfg_init_lock_file(target_zone, &zone_lock_env);
5581         if (zone_lock_env != NULL)
5582                 zoneadm_is_nested = B_TRUE;
5583 
5584         /*
5585          * If we are going to be operating on a single zone, retrieve its
5586          * brand type and determine whether it is native or not.
5587          */
5588         if ((target_zone != NULL) &&
5589             (strcmp(target_zone, GLOBAL_ZONENAME) != 0)) {
5590                 if (zone_get_brand(target_zone, target_brand,
5591                     sizeof (target_brand)) != Z_OK) {
5592                         zerror(gettext("missing or invalid brand"));
5593                         exit(Z_ERR);
5594                 }
5595                 is_native_zone = (strcmp(target_brand, NATIVE_BRAND_NAME) == 0);
5596         }
5597 
5598         err = parse_and_run(argc - optind, &argv[optind]);
5599 
5600         return (err);
5601 }