17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ee519a1fSgjelinek * Common Development and Distribution License (the "License"). 6ee519a1fSgjelinek * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217e362f58Scomay 227c478bd9Sstevel@tonic-gate /* 23ad02e316Sbatschul * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * zoneadm is a command interpreter for zone administration. It is all in 287c478bd9Sstevel@tonic-gate * C (i.e., no lex/yacc), and all the argument passing is argc/argv based. 297c478bd9Sstevel@tonic-gate * main() calls parse_and_run() which calls cmd_match(), then invokes the 307c478bd9Sstevel@tonic-gate * appropriate command's handler function. The rest of the program is the 317c478bd9Sstevel@tonic-gate * handler functions and their helper functions. 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * Some of the helper functions are used largely to simplify I18N: reducing 347c478bd9Sstevel@tonic-gate * the need for translation notes. This is particularly true of many of 357c478bd9Sstevel@tonic-gate * the zerror() calls: doing e.g. zerror(gettext("%s failed"), "foo") rather 367c478bd9Sstevel@tonic-gate * than zerror(gettext("foo failed")) with a translation note indicating 377c478bd9Sstevel@tonic-gate * that "foo" need not be translated. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <stdio.h> 417c478bd9Sstevel@tonic-gate #include <errno.h> 427c478bd9Sstevel@tonic-gate #include <unistd.h> 437c478bd9Sstevel@tonic-gate #include <signal.h> 447c478bd9Sstevel@tonic-gate #include <stdarg.h> 457c478bd9Sstevel@tonic-gate #include <ctype.h> 467c478bd9Sstevel@tonic-gate #include <stdlib.h> 477c478bd9Sstevel@tonic-gate #include <string.h> 487c478bd9Sstevel@tonic-gate #include <wait.h> 497c478bd9Sstevel@tonic-gate #include <zone.h> 507c478bd9Sstevel@tonic-gate #include <priv.h> 517c478bd9Sstevel@tonic-gate #include <locale.h> 527c478bd9Sstevel@tonic-gate #include <libintl.h> 537c478bd9Sstevel@tonic-gate #include <libzonecfg.h> 547c478bd9Sstevel@tonic-gate #include <bsm/adt.h> 559acbbeafSnn35248 #include <sys/brand.h> 567c478bd9Sstevel@tonic-gate #include <sys/param.h> 577c478bd9Sstevel@tonic-gate #include <sys/types.h> 587c478bd9Sstevel@tonic-gate #include <sys/stat.h> 597c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 607c478bd9Sstevel@tonic-gate #include <assert.h> 617c478bd9Sstevel@tonic-gate #include <sys/sockio.h> 627c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 637c478bd9Sstevel@tonic-gate #include <limits.h> 640b5de56dSgjelinek #include <dirent.h> 65555afedfScarlsonj #include <uuid/uuid.h> 667c478bd9Sstevel@tonic-gate #include <fcntl.h> 677c478bd9Sstevel@tonic-gate #include <door.h> 687c478bd9Sstevel@tonic-gate #include <macros.h> 697c478bd9Sstevel@tonic-gate #include <libgen.h> 70865e09a4Sgjelinek #include <fnmatch.h> 71e7f3c547Sgjelinek #include <sys/modctl.h> 729acbbeafSnn35248 #include <libbrand.h> 730209230bSgjelinek #include <libscf.h> 747ef01d19Sgjelinek #include <procfs.h> 75d9e728a2Sgjelinek #include <strings.h> 767c478bd9Sstevel@tonic-gate #include <pool.h> 777c478bd9Sstevel@tonic-gate #include <sys/pool.h> 780209230bSgjelinek #include <sys/priocntl.h> 790209230bSgjelinek #include <sys/fsspriocntl.h> 802b24ab6bSSebastien Roy #include <libdladm.h> 812b24ab6bSSebastien Roy #include <libdllink.h> 82cb8a054bSGlenn Faden #include <pwd.h> 83cb8a054bSGlenn Faden #include <auth_list.h> 84cb8a054bSGlenn Faden #include <auth_attr.h> 85cb8a054bSGlenn Faden #include <secdb.h> 867c478bd9Sstevel@tonic-gate 870b5de56dSgjelinek #include "zoneadm.h" 880b5de56dSgjelinek 897c478bd9Sstevel@tonic-gate #define MAXARGS 8 90cb8a054bSGlenn Faden #define SOURCE_ZONE (CMD_MAX + 1) 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* Reflects kernel zone entries */ 937c478bd9Sstevel@tonic-gate typedef struct zone_entry { 947c478bd9Sstevel@tonic-gate zoneid_t zid; 957c478bd9Sstevel@tonic-gate char zname[ZONENAME_MAX]; 967c478bd9Sstevel@tonic-gate char *zstate_str; 977c478bd9Sstevel@tonic-gate zone_state_t zstate_num; 989acbbeafSnn35248 char zbrand[MAXNAMELEN]; 997c478bd9Sstevel@tonic-gate char zroot[MAXPATHLEN]; 100555afedfScarlsonj char zuuid[UUID_PRINTABLE_STRING_LENGTH]; 101f4b3ec61Sdh155122 zone_iptype_t ziptype; 1027c478bd9Sstevel@tonic-gate } zone_entry_t; 1037c478bd9Sstevel@tonic-gate 10484561e8cStd153743 #define CLUSTER_BRAND_NAME "cluster" 10584561e8cStd153743 1067c478bd9Sstevel@tonic-gate static zone_entry_t *zents; 1077c478bd9Sstevel@tonic-gate static size_t nzents; 1087c478bd9Sstevel@tonic-gate 1091390a385Sgjelinek #define LOOPBACK_IF "lo0" 1101390a385Sgjelinek #define SOCKET_AF(af) (((af) == AF_UNSPEC) ? AF_INET : (af)) 1111390a385Sgjelinek 1121390a385Sgjelinek struct net_if { 1131390a385Sgjelinek char *name; 1141390a385Sgjelinek int af; 1151390a385Sgjelinek }; 1161390a385Sgjelinek 1177c478bd9Sstevel@tonic-gate /* 0755 is the default directory mode. */ 1187c478bd9Sstevel@tonic-gate #define DEFAULT_DIR_MODE \ 1197c478bd9Sstevel@tonic-gate (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate struct cmd { 1227c478bd9Sstevel@tonic-gate uint_t cmd_num; /* command number */ 1237c478bd9Sstevel@tonic-gate char *cmd_name; /* command name */ 1247c478bd9Sstevel@tonic-gate char *short_usage; /* short form help */ 1257c478bd9Sstevel@tonic-gate int (*handler)(int argc, char *argv[]); /* function to call */ 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate }; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate #define SHELP_HELP "help" 1303f2f09c1Sdp #define SHELP_BOOT "boot [-- boot_arguments]" 1317c478bd9Sstevel@tonic-gate #define SHELP_HALT "halt" 1327c478bd9Sstevel@tonic-gate #define SHELP_READY "ready" 1333f2f09c1Sdp #define SHELP_REBOOT "reboot [-- boot_arguments]" 1347c478bd9Sstevel@tonic-gate #define SHELP_LIST "list [-cipv]" 1357c478bd9Sstevel@tonic-gate #define SHELP_VERIFY "verify" 136ad02e316Sbatschul #define SHELP_INSTALL "install [brand-specific args]" 137ff17c8bfSgjelinek #define SHELP_UNINSTALL "uninstall [-F] [brand-specific args]" 138ff17c8bfSgjelinek #define SHELP_CLONE "clone [-m method] [-s <ZFS snapshot>] "\ 139ff17c8bfSgjelinek "[brand-specific args] zonename" 140865e09a4Sgjelinek #define SHELP_MOVE "move zonepath" 141ff17c8bfSgjelinek #define SHELP_DETACH "detach [-n] [brand-specific args]" 142ff17c8bfSgjelinek #define SHELP_ATTACH "attach [-F] [-n <path>] [brand-specific args]" 143555afedfScarlsonj #define SHELP_MARK "mark incomplete" 1447c478bd9Sstevel@tonic-gate 1459acbbeafSnn35248 #define EXEC_PREFIX "exec " 1469acbbeafSnn35248 #define EXEC_LEN (strlen(EXEC_PREFIX)) 1479acbbeafSnn35248 #define RMCOMMAND "/usr/bin/rm -rf" 1489acbbeafSnn35248 1499acbbeafSnn35248 static int cleanup_zonepath(char *, boolean_t); 1509acbbeafSnn35248 151f4b3ec61Sdh155122 1527c478bd9Sstevel@tonic-gate static int help_func(int argc, char *argv[]); 1537c478bd9Sstevel@tonic-gate static int ready_func(int argc, char *argv[]); 1547c478bd9Sstevel@tonic-gate static int boot_func(int argc, char *argv[]); 1557c478bd9Sstevel@tonic-gate static int halt_func(int argc, char *argv[]); 1567c478bd9Sstevel@tonic-gate static int reboot_func(int argc, char *argv[]); 1577c478bd9Sstevel@tonic-gate static int list_func(int argc, char *argv[]); 1587c478bd9Sstevel@tonic-gate static int verify_func(int argc, char *argv[]); 1597c478bd9Sstevel@tonic-gate static int install_func(int argc, char *argv[]); 1607c478bd9Sstevel@tonic-gate static int uninstall_func(int argc, char *argv[]); 161108322fbScarlsonj static int mount_func(int argc, char *argv[]); 162108322fbScarlsonj static int unmount_func(int argc, char *argv[]); 163865e09a4Sgjelinek static int clone_func(int argc, char *argv[]); 164865e09a4Sgjelinek static int move_func(int argc, char *argv[]); 165ee519a1fSgjelinek static int detach_func(int argc, char *argv[]); 166ee519a1fSgjelinek static int attach_func(int argc, char *argv[]); 167555afedfScarlsonj static int mark_func(int argc, char *argv[]); 1680209230bSgjelinek static int apply_func(int argc, char *argv[]); 169fbbfbc6eSjv227347 static int sysboot_func(int argc, char *argv[]); 1707c478bd9Sstevel@tonic-gate static int sanity_check(char *zone, int cmd_num, boolean_t running, 1719acbbeafSnn35248 boolean_t unsafe_when_running, boolean_t force); 1727c478bd9Sstevel@tonic-gate static int cmd_match(char *cmd); 173ce28b40eSzt129084 static int verify_details(int, char *argv[]); 174ce28b40eSzt129084 static int verify_brand(zone_dochandle_t, int, char *argv[]); 175ce28b40eSzt129084 static int invoke_brand_handler(int, char *argv[]); 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static struct cmd cmdtab[] = { 1787c478bd9Sstevel@tonic-gate { CMD_HELP, "help", SHELP_HELP, help_func }, 1797c478bd9Sstevel@tonic-gate { CMD_BOOT, "boot", SHELP_BOOT, boot_func }, 1807c478bd9Sstevel@tonic-gate { CMD_HALT, "halt", SHELP_HALT, halt_func }, 1817c478bd9Sstevel@tonic-gate { CMD_READY, "ready", SHELP_READY, ready_func }, 1827c478bd9Sstevel@tonic-gate { CMD_REBOOT, "reboot", SHELP_REBOOT, reboot_func }, 1837c478bd9Sstevel@tonic-gate { CMD_LIST, "list", SHELP_LIST, list_func }, 1847c478bd9Sstevel@tonic-gate { CMD_VERIFY, "verify", SHELP_VERIFY, verify_func }, 1857c478bd9Sstevel@tonic-gate { CMD_INSTALL, "install", SHELP_INSTALL, install_func }, 1867c478bd9Sstevel@tonic-gate { CMD_UNINSTALL, "uninstall", SHELP_UNINSTALL, 187108322fbScarlsonj uninstall_func }, 188865e09a4Sgjelinek /* mount and unmount are private commands for admin/install */ 189108322fbScarlsonj { CMD_MOUNT, "mount", NULL, mount_func }, 190865e09a4Sgjelinek { CMD_UNMOUNT, "unmount", NULL, unmount_func }, 191865e09a4Sgjelinek { CMD_CLONE, "clone", SHELP_CLONE, clone_func }, 192ee519a1fSgjelinek { CMD_MOVE, "move", SHELP_MOVE, move_func }, 193ee519a1fSgjelinek { CMD_DETACH, "detach", SHELP_DETACH, detach_func }, 194555afedfScarlsonj { CMD_ATTACH, "attach", SHELP_ATTACH, attach_func }, 1950209230bSgjelinek { CMD_MARK, "mark", SHELP_MARK, mark_func }, 196fbbfbc6eSjv227347 { CMD_APPLY, "apply", NULL, apply_func }, 197fbbfbc6eSjv227347 { CMD_SYSBOOT, "sysboot", NULL, sysboot_func } 1987c478bd9Sstevel@tonic-gate }; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* global variables */ 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate /* set early in main(), never modified thereafter, used all over the place */ 2037c478bd9Sstevel@tonic-gate static char *execname; 2049acbbeafSnn35248 static char target_brand[MAXNAMELEN]; 205e5816e35SEdward Pilatowicz static char default_brand[MAXPATHLEN]; 2067c478bd9Sstevel@tonic-gate static char *locale; 2070b5de56dSgjelinek char *target_zone; 208555afedfScarlsonj static char *target_uuid; 209cb8a054bSGlenn Faden char *username; 2107c478bd9Sstevel@tonic-gate 2110b5de56dSgjelinek char * 2127c478bd9Sstevel@tonic-gate cmd_to_str(int cmd_num) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 2157c478bd9Sstevel@tonic-gate return (cmdtab[cmd_num].cmd_name); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* This is a separate function because of gettext() wrapping. */ 2197c478bd9Sstevel@tonic-gate static char * 2207c478bd9Sstevel@tonic-gate long_help(int cmd_num) 2217c478bd9Sstevel@tonic-gate { 2227e362f58Scomay assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 2237c478bd9Sstevel@tonic-gate switch (cmd_num) { 2247c478bd9Sstevel@tonic-gate case CMD_HELP: 2257c478bd9Sstevel@tonic-gate return (gettext("Print usage message.")); 2267c478bd9Sstevel@tonic-gate case CMD_BOOT: 2273f2f09c1Sdp return (gettext("Activates (boots) specified zone. See " 2283f2f09c1Sdp "zoneadm(1m) for valid boot\n\targuments.")); 2297c478bd9Sstevel@tonic-gate case CMD_HALT: 2309e518655Sgjelinek return (gettext("Halts specified zone, bypassing shutdown " 2319e518655Sgjelinek "scripts and removing runtime\n\tresources of the zone.")); 2327c478bd9Sstevel@tonic-gate case CMD_READY: 2339e518655Sgjelinek return (gettext("Prepares a zone for running applications but " 2349e518655Sgjelinek "does not start any user\n\tprocesses in the zone.")); 2357c478bd9Sstevel@tonic-gate case CMD_REBOOT: 2369e518655Sgjelinek return (gettext("Restarts the zone (equivalent to a halt / " 2373f2f09c1Sdp "boot sequence).\n\tFails if the zone is not active. " 2383f2f09c1Sdp "See zoneadm(1m) for valid boot\n\targuments.")); 2397c478bd9Sstevel@tonic-gate case CMD_LIST: 2407c478bd9Sstevel@tonic-gate return (gettext("Lists the current zones, or a " 2417c478bd9Sstevel@tonic-gate "specific zone if indicated. By default,\n\tall " 2427c478bd9Sstevel@tonic-gate "running zones are listed, though this can be " 2437c478bd9Sstevel@tonic-gate "expanded to all\n\tinstalled zones with the -i " 2447c478bd9Sstevel@tonic-gate "option or all configured zones with the\n\t-c " 245555afedfScarlsonj "option. When used with the general -z <zone> and/or -u " 246555afedfScarlsonj "<uuid-match>\n\toptions, lists only the specified " 247555afedfScarlsonj "matching zone, but lists it\n\tregardless of its state, " 248555afedfScarlsonj "and the -i and -c options are disallowed. The\n\t-v " 249555afedfScarlsonj "option can be used to display verbose information: zone " 250555afedfScarlsonj "name, id,\n\tcurrent state, root directory and options. " 251555afedfScarlsonj "The -p option can be used\n\tto request machine-parsable " 252555afedfScarlsonj "output. The -v and -p options are mutually\n\texclusive." 253555afedfScarlsonj " If neither -v nor -p is used, just the zone name is " 254555afedfScarlsonj "listed.")); 2557c478bd9Sstevel@tonic-gate case CMD_VERIFY: 2567c478bd9Sstevel@tonic-gate return (gettext("Check to make sure the configuration " 2577c478bd9Sstevel@tonic-gate "can safely be instantiated\n\ton the machine: " 2587c478bd9Sstevel@tonic-gate "physical network interfaces exist, etc.")); 2597c478bd9Sstevel@tonic-gate case CMD_INSTALL: 2600b5de56dSgjelinek return (gettext("Install the configuration on to the system. " 261ad02e316Sbatschul "All arguments are passed to the brand installation " 262ff17c8bfSgjelinek "function;\n\tsee brands(5) for more information.")); 2637c478bd9Sstevel@tonic-gate case CMD_UNINSTALL: 2649e518655Sgjelinek return (gettext("Uninstall the configuration from the system. " 265ff17c8bfSgjelinek "The -F flag can be used\n\tto force the action. All " 266ff17c8bfSgjelinek "other arguments are passed to the brand\n\tuninstall " 267ff17c8bfSgjelinek "function; see brands(5) for more information.")); 268865e09a4Sgjelinek case CMD_CLONE: 2690b5de56dSgjelinek return (gettext("Clone the installation of another zone. " 2700b5de56dSgjelinek "The -m option can be used to\n\tspecify 'copy' which " 2710b5de56dSgjelinek "forces a copy of the source zone. The -s option\n\t" 2720b5de56dSgjelinek "can be used to specify the name of a ZFS snapshot " 2730b5de56dSgjelinek "that was taken from\n\ta previous clone command. The " 2740b5de56dSgjelinek "snapshot will be used as the source\n\tinstead of " 275ff17c8bfSgjelinek "creating a new ZFS snapshot. All other arguments are " 276ff17c8bfSgjelinek "passed\n\tto the brand clone function; see " 277ff17c8bfSgjelinek "brands(5) for more information.")); 278865e09a4Sgjelinek case CMD_MOVE: 279865e09a4Sgjelinek return (gettext("Move the zone to a new zonepath.")); 2809e518655Sgjelinek case CMD_DETACH: 2819e518655Sgjelinek return (gettext("Detach the zone from the system. The zone " 2829e518655Sgjelinek "state is changed to\n\t'configured' (but the files under " 2839e518655Sgjelinek "the zonepath are untouched).\n\tThe zone can subsequently " 2849e518655Sgjelinek "be attached, or can be moved to another\n\tsystem and " 2858cd327d5Sgjelinek "attached there. The -n option can be used to specify\n\t" 2868cd327d5Sgjelinek "'no-execute' mode. When -n is used, the information " 2878cd327d5Sgjelinek "needed to attach\n\tthe zone is sent to standard output " 288ff17c8bfSgjelinek "but the zone is not actually\n\tdetached. All other " 289ff17c8bfSgjelinek "arguments are passed to the brand detach function;\n\tsee " 290ff17c8bfSgjelinek "brands(5) for more information.")); 2919e518655Sgjelinek case CMD_ATTACH: 2929e518655Sgjelinek return (gettext("Attach the zone to the system. The zone " 2939e518655Sgjelinek "state must be 'configured'\n\tprior to attach; upon " 2949e518655Sgjelinek "successful completion, the zone state will be\n\t" 2959e518655Sgjelinek "'installed'. The system software on the current " 2969e518655Sgjelinek "system must be\n\tcompatible with the software on the " 297ff17c8bfSgjelinek "zone's original system.\n\tSpecify -F " 2986cfd72c6Sgjelinek "to force the attach and skip software compatibility " 2996cfd72c6Sgjelinek "tests.\n\tThe -n option can be used to specify " 3006cfd72c6Sgjelinek "'no-execute' mode. When -n is\n\tused, the information " 3016cfd72c6Sgjelinek "needed to attach the zone is read from the\n\tspecified " 3026cfd72c6Sgjelinek "path and the configuration is only validated. The path " 303ff17c8bfSgjelinek "can\n\tbe '-' to specify standard input. The -F and -n " 304ff17c8bfSgjelinek "options are mutually\n\texclusive. All other arguments " 305ff17c8bfSgjelinek "are passed to the brand attach\n\tfunction; see " 306ff17c8bfSgjelinek "brands(5) for more information.")); 307555afedfScarlsonj case CMD_MARK: 308555afedfScarlsonj return (gettext("Set the state of the zone. This can be used " 309555afedfScarlsonj "to force the zone\n\tstate to 'incomplete' " 310555afedfScarlsonj "administratively if some activity has rendered\n\tthe " 311555afedfScarlsonj "zone permanently unusable. The only valid state that " 312555afedfScarlsonj "may be\n\tspecified is 'incomplete'.")); 313108322fbScarlsonj default: 314108322fbScarlsonj return (""); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3177e362f58Scomay return (NULL); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * Called with explicit B_TRUE when help is explicitly requested, B_FALSE for 3227c478bd9Sstevel@tonic-gate * unexpected errors. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate static int 3267c478bd9Sstevel@tonic-gate usage(boolean_t explicit) 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate int i; 3297c478bd9Sstevel@tonic-gate FILE *fd = explicit ? stdout : stderr; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate (void) fprintf(fd, "%s:\t%s help\n", gettext("usage"), execname); 332555afedfScarlsonj (void) fprintf(fd, "\t%s [-z <zone>] [-u <uuid-match>] list\n", 333555afedfScarlsonj execname); 334555afedfScarlsonj (void) fprintf(fd, "\t%s {-z <zone>|-u <uuid-match>} <%s>\n", execname, 3357c478bd9Sstevel@tonic-gate gettext("subcommand")); 3367c478bd9Sstevel@tonic-gate (void) fprintf(fd, "\n%s:\n\n", gettext("Subcommands")); 3377c478bd9Sstevel@tonic-gate for (i = CMD_MIN; i <= CMD_MAX; i++) { 338108322fbScarlsonj if (cmdtab[i].short_usage == NULL) 339108322fbScarlsonj continue; 3407c478bd9Sstevel@tonic-gate (void) fprintf(fd, "%s\n", cmdtab[i].short_usage); 3417c478bd9Sstevel@tonic-gate if (explicit) 3427c478bd9Sstevel@tonic-gate (void) fprintf(fd, "\t%s\n\n", long_help(i)); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate if (!explicit) 3457c478bd9Sstevel@tonic-gate (void) fputs("\n", fd); 3467c478bd9Sstevel@tonic-gate return (Z_USAGE); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate static void 3507c478bd9Sstevel@tonic-gate sub_usage(char *short_usage, int cmd_num) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s:\t%s\n", gettext("usage"), short_usage); 3537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\t%s\n", long_help(cmd_num)); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * zperror() is like perror(3c) except that this also prints the executable 3587c478bd9Sstevel@tonic-gate * name at the start of the message, and takes a boolean indicating whether 3597c478bd9Sstevel@tonic-gate * to call libc'c strerror() or that from libzonecfg. 3607c478bd9Sstevel@tonic-gate */ 3617c478bd9Sstevel@tonic-gate 3620b5de56dSgjelinek void 3637c478bd9Sstevel@tonic-gate zperror(const char *str, boolean_t zonecfg_error) 3647c478bd9Sstevel@tonic-gate { 3657c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s: %s\n", execname, str, 3667c478bd9Sstevel@tonic-gate zonecfg_error ? zonecfg_strerror(errno) : strerror(errno)); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * zperror2() is very similar to zperror() above, except it also prints a 3717c478bd9Sstevel@tonic-gate * supplied zone name after the executable. 3727c478bd9Sstevel@tonic-gate * 3737c478bd9Sstevel@tonic-gate * All current consumers of this function want libzonecfg's strerror() rather 3747c478bd9Sstevel@tonic-gate * than libc's; if this ever changes, this function can be made more generic 3757c478bd9Sstevel@tonic-gate * like zperror() above. 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate 3780b5de56dSgjelinek void 3797c478bd9Sstevel@tonic-gate zperror2(const char *zone, const char *str) 3807c478bd9Sstevel@tonic-gate { 3817c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s: %s: %s\n", execname, zone, str, 3827c478bd9Sstevel@tonic-gate zonecfg_strerror(errno)); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */ 3860b5de56dSgjelinek void 3877c478bd9Sstevel@tonic-gate zerror(const char *fmt, ...) 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate va_list alist; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate va_start(alist, fmt); 3927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", execname); 3937c478bd9Sstevel@tonic-gate if (target_zone != NULL) 3947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "zone '%s': ", target_zone); 3957c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, alist); 3967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 3977c478bd9Sstevel@tonic-gate va_end(alist); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate static void * 4017c478bd9Sstevel@tonic-gate safe_calloc(size_t nelem, size_t elsize) 4027c478bd9Sstevel@tonic-gate { 4037c478bd9Sstevel@tonic-gate void *r = calloc(nelem, elsize); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate if (r == NULL) { 4067c478bd9Sstevel@tonic-gate zerror(gettext("failed to allocate %lu bytes: %s"), 4077c478bd9Sstevel@tonic-gate (ulong_t)nelem * elsize, strerror(errno)); 4087c478bd9Sstevel@tonic-gate exit(Z_ERR); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate return (r); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate static void 4147c478bd9Sstevel@tonic-gate zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable) 4157c478bd9Sstevel@tonic-gate { 4167c478bd9Sstevel@tonic-gate static boolean_t firsttime = B_TRUE; 417f4b3ec61Sdh155122 char *ip_type_str; 418f4b3ec61Sdh155122 4192766118bS /* Skip a zone that shutdown while we were collecting data. */ 4202766118bS if (zent->zname[0] == '\0') 4212766118bS return; 4222766118bS 423f4b3ec61Sdh155122 if (zent->ziptype == ZS_EXCLUSIVE) 424f4b3ec61Sdh155122 ip_type_str = "excl"; 425f4b3ec61Sdh155122 else 426f4b3ec61Sdh155122 ip_type_str = "shared"; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate assert(!(verbose && parsable)); 4297c478bd9Sstevel@tonic-gate if (firsttime && verbose) { 4307c478bd9Sstevel@tonic-gate firsttime = B_FALSE; 431f4b3ec61Sdh155122 (void) printf("%*s %-16s %-10s %-30s %-8s %-6s\n", 432f4b3ec61Sdh155122 ZONEID_WIDTH, "ID", "NAME", "STATUS", "PATH", "BRAND", 433f4b3ec61Sdh155122 "IP"); 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate if (!verbose) { 436555afedfScarlsonj char *cp, *clim; 437555afedfScarlsonj 4387c478bd9Sstevel@tonic-gate if (!parsable) { 4397c478bd9Sstevel@tonic-gate (void) printf("%s\n", zent->zname); 4407c478bd9Sstevel@tonic-gate return; 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate if (zent->zid == ZONE_ID_UNDEFINED) 4437c478bd9Sstevel@tonic-gate (void) printf("-"); 4447c478bd9Sstevel@tonic-gate else 4457c478bd9Sstevel@tonic-gate (void) printf("%lu", zent->zid); 446555afedfScarlsonj (void) printf(":%s:%s:", zent->zname, zent->zstate_str); 447555afedfScarlsonj cp = zent->zroot; 448555afedfScarlsonj while ((clim = strchr(cp, ':')) != NULL) { 449555afedfScarlsonj (void) printf("%.*s\\:", clim - cp, cp); 450555afedfScarlsonj cp = clim + 1; 451555afedfScarlsonj } 452f4b3ec61Sdh155122 (void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand, 453f4b3ec61Sdh155122 ip_type_str); 4547c478bd9Sstevel@tonic-gate return; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate if (zent->zstate_str != NULL) { 4577c478bd9Sstevel@tonic-gate if (zent->zid == ZONE_ID_UNDEFINED) 4587c478bd9Sstevel@tonic-gate (void) printf("%*s", ZONEID_WIDTH, "-"); 4597c478bd9Sstevel@tonic-gate else 4607c478bd9Sstevel@tonic-gate (void) printf("%*lu", ZONEID_WIDTH, zent->zid); 461f4b3ec61Sdh155122 (void) printf(" %-16s %-10s %-30s %-8s %-6s\n", zent->zname, 462f4b3ec61Sdh155122 zent->zstate_str, zent->zroot, zent->zbrand, ip_type_str); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate static int 467108322fbScarlsonj lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent) 4687c478bd9Sstevel@tonic-gate { 46945916cd2Sjpk char root[MAXPATHLEN], *cp; 4707c478bd9Sstevel@tonic-gate int err; 471555afedfScarlsonj uuid_t uuid; 4722766118bS zone_dochandle_t handle; 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate (void) strlcpy(zent->zname, zone_name, sizeof (zent->zname)); 4757c478bd9Sstevel@tonic-gate (void) strlcpy(zent->zroot, "???", sizeof (zent->zroot)); 4769acbbeafSnn35248 (void) strlcpy(zent->zbrand, "???", sizeof (zent->zbrand)); 4777c478bd9Sstevel@tonic-gate zent->zstate_str = "???"; 4787c478bd9Sstevel@tonic-gate 479108322fbScarlsonj zent->zid = zid; 4807c478bd9Sstevel@tonic-gate 481555afedfScarlsonj if (zonecfg_get_uuid(zone_name, uuid) == Z_OK && 482555afedfScarlsonj !uuid_is_null(uuid)) 483555afedfScarlsonj uuid_unparse(uuid, zent->zuuid); 484555afedfScarlsonj else 485555afedfScarlsonj zent->zuuid[0] = '\0'; 486555afedfScarlsonj 48745916cd2Sjpk /* 48845916cd2Sjpk * For labeled zones which query the zone path of lower-level 48945916cd2Sjpk * zones, the path needs to be adjusted to drop the final 49045916cd2Sjpk * "/root" component. This adjusted path is then useful 49145916cd2Sjpk * for reading down any exported directories from the 49245916cd2Sjpk * lower-level zone. 49345916cd2Sjpk */ 49445916cd2Sjpk if (is_system_labeled() && zent->zid != ZONE_ID_UNDEFINED) { 49545916cd2Sjpk if (zone_getattr(zent->zid, ZONE_ATTR_ROOT, zent->zroot, 49645916cd2Sjpk sizeof (zent->zroot)) == -1) { 49745916cd2Sjpk zperror2(zent->zname, 49845916cd2Sjpk gettext("could not get zone path.")); 49945916cd2Sjpk return (Z_ERR); 50045916cd2Sjpk } 50145916cd2Sjpk cp = zent->zroot + strlen(zent->zroot) - 5; 50245916cd2Sjpk if (cp > zent->zroot && strcmp(cp, "/root") == 0) 50345916cd2Sjpk *cp = 0; 50445916cd2Sjpk } else { 50545916cd2Sjpk if ((err = zone_get_zonepath(zent->zname, root, 50645916cd2Sjpk sizeof (root))) != Z_OK) { 5077c478bd9Sstevel@tonic-gate errno = err; 50845916cd2Sjpk zperror2(zent->zname, 50945916cd2Sjpk gettext("could not get zone path.")); 5107c478bd9Sstevel@tonic-gate return (Z_ERR); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate (void) strlcpy(zent->zroot, root, sizeof (zent->zroot)); 51345916cd2Sjpk } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate if ((err = zone_get_state(zent->zname, &zent->zstate_num)) != Z_OK) { 5167c478bd9Sstevel@tonic-gate errno = err; 5177c478bd9Sstevel@tonic-gate zperror2(zent->zname, gettext("could not get state")); 5187c478bd9Sstevel@tonic-gate return (Z_ERR); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate zent->zstate_str = zone_state_str(zent->zstate_num); 521bafa7067Snn35248 522bafa7067Snn35248 /* 523bafa7067Snn35248 * A zone's brand is only available in the .xml file describing it, 524bafa7067Snn35248 * which is only visible to the global zone. This causes 525bafa7067Snn35248 * zone_get_brand() to fail when called from within a non-global 526bafa7067Snn35248 * zone. Fortunately we only do this on labeled systems, where we 527bafa7067Snn35248 * know all zones are native. 528bafa7067Snn35248 */ 529bafa7067Snn35248 if (getzoneid() != GLOBAL_ZONEID) { 530bafa7067Snn35248 assert(is_system_labeled() != 0); 531e5816e35SEdward Pilatowicz (void) strlcpy(zent->zbrand, default_brand, 532bafa7067Snn35248 sizeof (zent->zbrand)); 533bafa7067Snn35248 } else if (zone_get_brand(zent->zname, zent->zbrand, 5349acbbeafSnn35248 sizeof (zent->zbrand)) != Z_OK) { 5359acbbeafSnn35248 zperror2(zent->zname, gettext("could not get brand name")); 5369acbbeafSnn35248 return (Z_ERR); 5379acbbeafSnn35248 } 5387c478bd9Sstevel@tonic-gate 539f4b3ec61Sdh155122 /* 540f4b3ec61Sdh155122 * Get ip type of the zone. 541f4b3ec61Sdh155122 * Note for global zone, ZS_SHARED is set always. 542f4b3ec61Sdh155122 */ 543f4b3ec61Sdh155122 if (zid == GLOBAL_ZONEID) { 544f4b3ec61Sdh155122 zent->ziptype = ZS_SHARED; 5452766118bS return (Z_OK); 5462766118bS } 547f4b3ec61Sdh155122 5482766118bS /* 5492766118bS * There is a race condition where the zone could boot while 5502766118bS * we're walking the index file. In this case the zone state 5512766118bS * could be seen as running from the call above, but the zoneid 5522766118bS * would be undefined. 5532766118bS * 5542766118bS * There is also a race condition where the zone could shutdown after 5552766118bS * we got its running state above. This is also not an error and 5562766118bS * we fall back to getting the ziptype from the zone configuration. 5572766118bS */ 5582766118bS if (zent->zstate_num == ZONE_STATE_RUNNING && 5592766118bS zid != ZONE_ID_UNDEFINED) { 560f4b3ec61Sdh155122 ushort_t flags; 561f4b3ec61Sdh155122 562f4b3ec61Sdh155122 if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags, 5632766118bS sizeof (flags)) >= 0) { 564f4b3ec61Sdh155122 if (flags & ZF_NET_EXCL) 565f4b3ec61Sdh155122 zent->ziptype = ZS_EXCLUSIVE; 566f4b3ec61Sdh155122 else 567f4b3ec61Sdh155122 zent->ziptype = ZS_SHARED; 5682766118bS return (Z_OK); 5692766118bS } 5702766118bS } 571f4b3ec61Sdh155122 572f4b3ec61Sdh155122 if ((handle = zonecfg_init_handle()) == NULL) { 5732766118bS zperror2(zent->zname, gettext("could not init handle")); 574f4b3ec61Sdh155122 return (Z_ERR); 575f4b3ec61Sdh155122 } 5762766118bS if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) { 5772766118bS zperror2(zent->zname, gettext("could not get handle")); 578f4b3ec61Sdh155122 zonecfg_fini_handle(handle); 579f4b3ec61Sdh155122 return (Z_ERR); 580f4b3ec61Sdh155122 } 581f4b3ec61Sdh155122 5822766118bS if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) { 5832766118bS zperror2(zent->zname, gettext("could not get ip-type")); 584f4b3ec61Sdh155122 zonecfg_fini_handle(handle); 585f4b3ec61Sdh155122 return (Z_ERR); 586f4b3ec61Sdh155122 } 587f4b3ec61Sdh155122 zonecfg_fini_handle(handle); 588f4b3ec61Sdh155122 5897c478bd9Sstevel@tonic-gate return (Z_OK); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* 5937c478bd9Sstevel@tonic-gate * fetch_zents() calls zone_list(2) to find out how many zones are running 5947c478bd9Sstevel@tonic-gate * (which is stored in the global nzents), then calls zone_list(2) again 5957c478bd9Sstevel@tonic-gate * to fetch the list of running zones (stored in the global zents). This 5967c478bd9Sstevel@tonic-gate * function may be called multiple times, so if zents is already set, we 5977c478bd9Sstevel@tonic-gate * return immediately to save work. 5982766118bS * 5992766118bS * Note that the data about running zones can change while this function 6002766118bS * is running, so its possible that the list of zones will have empty slots 6012766118bS * at the end. 6027c478bd9Sstevel@tonic-gate */ 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate static int 605108322fbScarlsonj fetch_zents(void) 6067c478bd9Sstevel@tonic-gate { 6077c478bd9Sstevel@tonic-gate zoneid_t *zids = NULL; 6087c478bd9Sstevel@tonic-gate uint_t nzents_saved; 609108322fbScarlsonj int i, retv; 610108322fbScarlsonj FILE *fp; 611108322fbScarlsonj boolean_t inaltroot; 612108322fbScarlsonj zone_entry_t *zentp; 613*c8845d44SSusan Kamm-Worrell const char *altroot; 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (nzents > 0) 6167c478bd9Sstevel@tonic-gate return (Z_OK); 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate if (zone_list(NULL, &nzents) != 0) { 6197c478bd9Sstevel@tonic-gate zperror(gettext("failed to get zoneid list"), B_FALSE); 6207c478bd9Sstevel@tonic-gate return (Z_ERR); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate again: 6247c478bd9Sstevel@tonic-gate if (nzents == 0) 6257c478bd9Sstevel@tonic-gate return (Z_OK); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate zids = safe_calloc(nzents, sizeof (zoneid_t)); 6287c478bd9Sstevel@tonic-gate nzents_saved = nzents; 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate if (zone_list(zids, &nzents) != 0) { 6317c478bd9Sstevel@tonic-gate zperror(gettext("failed to get zone list"), B_FALSE); 6327c478bd9Sstevel@tonic-gate free(zids); 6337c478bd9Sstevel@tonic-gate return (Z_ERR); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate if (nzents != nzents_saved) { 6367c478bd9Sstevel@tonic-gate /* list changed, try again */ 6377c478bd9Sstevel@tonic-gate free(zids); 6387c478bd9Sstevel@tonic-gate goto again; 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate zents = safe_calloc(nzents, sizeof (zone_entry_t)); 6427c478bd9Sstevel@tonic-gate 643108322fbScarlsonj inaltroot = zonecfg_in_alt_root(); 644*c8845d44SSusan Kamm-Worrell if (inaltroot) { 645108322fbScarlsonj fp = zonecfg_open_scratch("", B_FALSE); 646*c8845d44SSusan Kamm-Worrell altroot = zonecfg_get_root(); 647*c8845d44SSusan Kamm-Worrell } else { 648108322fbScarlsonj fp = NULL; 649*c8845d44SSusan Kamm-Worrell } 650108322fbScarlsonj zentp = zents; 651108322fbScarlsonj retv = Z_OK; 6527c478bd9Sstevel@tonic-gate for (i = 0; i < nzents; i++) { 6537c478bd9Sstevel@tonic-gate char name[ZONENAME_MAX]; 654108322fbScarlsonj char altname[ZONENAME_MAX]; 655*c8845d44SSusan Kamm-Worrell char rev_altroot[MAXPATHLEN]; 6567c478bd9Sstevel@tonic-gate 657108322fbScarlsonj if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) { 6582766118bS /* 6592766118bS * There is a race condition where the zone may have 6602766118bS * shutdown since we retrieved the number of running 6612766118bS * zones above. This is not an error, there will be 6622766118bS * an empty slot at the end of the list. 6632766118bS */ 664108322fbScarlsonj continue; 6657c478bd9Sstevel@tonic-gate } 666108322fbScarlsonj if (zonecfg_is_scratch(name)) { 667108322fbScarlsonj /* Ignore scratch zones by default */ 668108322fbScarlsonj if (!inaltroot) 669108322fbScarlsonj continue; 670108322fbScarlsonj if (fp == NULL || 671108322fbScarlsonj zonecfg_reverse_scratch(fp, name, altname, 672*c8845d44SSusan Kamm-Worrell sizeof (altname), rev_altroot, 673*c8845d44SSusan Kamm-Worrell sizeof (rev_altroot)) == -1) { 6745ee84fbdSgjelinek zerror(gettext("could not resolve scratch " 675108322fbScarlsonj "zone %s"), name); 676108322fbScarlsonj retv = Z_ERR; 677108322fbScarlsonj continue; 678108322fbScarlsonj } 679*c8845d44SSusan Kamm-Worrell /* Ignore zones in other alternate roots */ 680*c8845d44SSusan Kamm-Worrell if (strcmp(rev_altroot, altroot) != 0) 681*c8845d44SSusan Kamm-Worrell continue; 682108322fbScarlsonj (void) strcpy(name, altname); 683108322fbScarlsonj } else { 684108322fbScarlsonj /* Ignore non-scratch when in an alternate root */ 685108322fbScarlsonj if (inaltroot && strcmp(name, GLOBAL_ZONENAME) != 0) 686108322fbScarlsonj continue; 687108322fbScarlsonj } 688108322fbScarlsonj if (lookup_zone_info(name, zids[i], zentp) != Z_OK) { 6892766118bS /* 6902766118bS * There is a race condition where the zone may have 6912766118bS * shutdown since we retrieved the number of running 6922766118bS * zones above. This is not an error, there will be 6932766118bS * an empty slot at the end of the list. 6942766118bS */ 695108322fbScarlsonj continue; 696108322fbScarlsonj } 697108322fbScarlsonj zentp++; 698108322fbScarlsonj } 699108322fbScarlsonj nzents = zentp - zents; 700108322fbScarlsonj if (fp != NULL) 701108322fbScarlsonj zonecfg_close_scratch(fp); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate free(zids); 704108322fbScarlsonj return (retv); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 707108322fbScarlsonj static int 7087c478bd9Sstevel@tonic-gate zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable) 7097c478bd9Sstevel@tonic-gate { 7107c478bd9Sstevel@tonic-gate int i; 7117c478bd9Sstevel@tonic-gate zone_entry_t zent; 7127c478bd9Sstevel@tonic-gate FILE *cookie; 7137c478bd9Sstevel@tonic-gate char *name; 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * First get the list of running zones from the kernel and print them. 7177c478bd9Sstevel@tonic-gate * If that is all we need, then return. 7187c478bd9Sstevel@tonic-gate */ 719108322fbScarlsonj if ((i = fetch_zents()) != Z_OK) { 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * No need for error messages; fetch_zents() has already taken 7227c478bd9Sstevel@tonic-gate * care of this. 7237c478bd9Sstevel@tonic-gate */ 724108322fbScarlsonj return (i); 7257c478bd9Sstevel@tonic-gate } 726108322fbScarlsonj for (i = 0; i < nzents; i++) 7277c478bd9Sstevel@tonic-gate zone_print(&zents[i], verbose, parsable); 7287c478bd9Sstevel@tonic-gate if (min_state >= ZONE_STATE_RUNNING) 729108322fbScarlsonj return (Z_OK); 7307c478bd9Sstevel@tonic-gate /* 7317c478bd9Sstevel@tonic-gate * Next, get the full list of zones from the configuration, skipping 7327c478bd9Sstevel@tonic-gate * any we have already printed. 7337c478bd9Sstevel@tonic-gate */ 7347c478bd9Sstevel@tonic-gate cookie = setzoneent(); 7357c478bd9Sstevel@tonic-gate while ((name = getzoneent(cookie)) != NULL) { 7367c478bd9Sstevel@tonic-gate for (i = 0; i < nzents; i++) { 7377c478bd9Sstevel@tonic-gate if (strcmp(zents[i].zname, name) == 0) 7387c478bd9Sstevel@tonic-gate break; 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate if (i < nzents) { 7417c478bd9Sstevel@tonic-gate free(name); 7427c478bd9Sstevel@tonic-gate continue; 7437c478bd9Sstevel@tonic-gate } 744108322fbScarlsonj if (lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) { 7457c478bd9Sstevel@tonic-gate free(name); 7467c478bd9Sstevel@tonic-gate continue; 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate free(name); 7497c478bd9Sstevel@tonic-gate if (zent.zstate_num >= min_state) 7507c478bd9Sstevel@tonic-gate zone_print(&zent, verbose, parsable); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate endzoneent(cookie); 753108322fbScarlsonj return (Z_OK); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 756c9f134eaSjv227347 /* 757c9f134eaSjv227347 * Retrieve a zone entry by name. Returns NULL if no such zone exists. 758c9f134eaSjv227347 */ 7597c478bd9Sstevel@tonic-gate static zone_entry_t * 760c9f134eaSjv227347 lookup_running_zone(const char *str) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate int i; 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate if (fetch_zents() != Z_OK) 7657c478bd9Sstevel@tonic-gate return (NULL); 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate for (i = 0; i < nzents; i++) { 7687c478bd9Sstevel@tonic-gate if (strcmp(str, zents[i].zname) == 0) 7697c478bd9Sstevel@tonic-gate return (&zents[i]); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate return (NULL); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate /* 7757c478bd9Sstevel@tonic-gate * Check a bit in a mode_t: if on is B_TRUE, that bit should be on; if 7767c478bd9Sstevel@tonic-gate * B_FALSE, it should be off. Return B_TRUE if the mode is bad (incorrect). 7777c478bd9Sstevel@tonic-gate */ 7787c478bd9Sstevel@tonic-gate static boolean_t 7797c478bd9Sstevel@tonic-gate bad_mode_bit(mode_t mode, mode_t bit, boolean_t on, char *file) 7807c478bd9Sstevel@tonic-gate { 7817c478bd9Sstevel@tonic-gate char *str; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate assert(bit == S_IRUSR || bit == S_IWUSR || bit == S_IXUSR || 7847c478bd9Sstevel@tonic-gate bit == S_IRGRP || bit == S_IWGRP || bit == S_IXGRP || 7857c478bd9Sstevel@tonic-gate bit == S_IROTH || bit == S_IWOTH || bit == S_IXOTH); 7867c478bd9Sstevel@tonic-gate /* 7877c478bd9Sstevel@tonic-gate * TRANSLATION_NOTE 7887c478bd9Sstevel@tonic-gate * The strings below will be used as part of a larger message, 7897c478bd9Sstevel@tonic-gate * either: 7907c478bd9Sstevel@tonic-gate * (file name) must be (owner|group|world) (read|writ|execut)able 7917c478bd9Sstevel@tonic-gate * or 7927c478bd9Sstevel@tonic-gate * (file name) must not be (owner|group|world) (read|writ|execut)able 7937c478bd9Sstevel@tonic-gate */ 7947c478bd9Sstevel@tonic-gate switch (bit) { 7957c478bd9Sstevel@tonic-gate case S_IRUSR: 7967c478bd9Sstevel@tonic-gate str = gettext("owner readable"); 7977c478bd9Sstevel@tonic-gate break; 7987c478bd9Sstevel@tonic-gate case S_IWUSR: 7997c478bd9Sstevel@tonic-gate str = gettext("owner writable"); 8007c478bd9Sstevel@tonic-gate break; 8017c478bd9Sstevel@tonic-gate case S_IXUSR: 8027c478bd9Sstevel@tonic-gate str = gettext("owner executable"); 8037c478bd9Sstevel@tonic-gate break; 8047c478bd9Sstevel@tonic-gate case S_IRGRP: 8057c478bd9Sstevel@tonic-gate str = gettext("group readable"); 8067c478bd9Sstevel@tonic-gate break; 8077c478bd9Sstevel@tonic-gate case S_IWGRP: 8087c478bd9Sstevel@tonic-gate str = gettext("group writable"); 8097c478bd9Sstevel@tonic-gate break; 8107c478bd9Sstevel@tonic-gate case S_IXGRP: 8117c478bd9Sstevel@tonic-gate str = gettext("group executable"); 8127c478bd9Sstevel@tonic-gate break; 8137c478bd9Sstevel@tonic-gate case S_IROTH: 8147c478bd9Sstevel@tonic-gate str = gettext("world readable"); 8157c478bd9Sstevel@tonic-gate break; 8167c478bd9Sstevel@tonic-gate case S_IWOTH: 8177c478bd9Sstevel@tonic-gate str = gettext("world writable"); 8187c478bd9Sstevel@tonic-gate break; 8197c478bd9Sstevel@tonic-gate case S_IXOTH: 8207c478bd9Sstevel@tonic-gate str = gettext("world executable"); 8217c478bd9Sstevel@tonic-gate break; 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate if ((mode & bit) == (on ? 0 : bit)) { 8247c478bd9Sstevel@tonic-gate /* 8257c478bd9Sstevel@tonic-gate * TRANSLATION_NOTE 8267c478bd9Sstevel@tonic-gate * The first parameter below is a file name; the second 8277c478bd9Sstevel@tonic-gate * is one of the "(owner|group|world) (read|writ|execut)able" 8287c478bd9Sstevel@tonic-gate * strings from above. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate /* 8317c478bd9Sstevel@tonic-gate * The code below could be simplified but not in a way 8327c478bd9Sstevel@tonic-gate * that would easily translate to non-English locales. 8337c478bd9Sstevel@tonic-gate */ 8347c478bd9Sstevel@tonic-gate if (on) { 8357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s must be %s.\n"), 8367c478bd9Sstevel@tonic-gate file, str); 8377c478bd9Sstevel@tonic-gate } else { 8387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s must not be %s.\n"), 8397c478bd9Sstevel@tonic-gate file, str); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate return (B_TRUE); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate return (B_FALSE); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate /* 8477c478bd9Sstevel@tonic-gate * We want to make sure that no zone has its zone path as a child node 8487c478bd9Sstevel@tonic-gate * (in the directory sense) of any other. We do that by comparing this 8497c478bd9Sstevel@tonic-gate * zone's path to the path of all other (non-global) zones. The comparison 8507c478bd9Sstevel@tonic-gate * in each case is simple: add '/' to the end of the path, then do a 8517c478bd9Sstevel@tonic-gate * strncmp() of the two paths, using the length of the shorter one. 8527c478bd9Sstevel@tonic-gate */ 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate static int 8557c478bd9Sstevel@tonic-gate crosscheck_zonepaths(char *path) 8567c478bd9Sstevel@tonic-gate { 8577c478bd9Sstevel@tonic-gate char rpath[MAXPATHLEN]; /* resolved path */ 8587c478bd9Sstevel@tonic-gate char path_copy[MAXPATHLEN]; /* copy of original path */ 8597c478bd9Sstevel@tonic-gate char rpath_copy[MAXPATHLEN]; /* copy of original rpath */ 8607c478bd9Sstevel@tonic-gate struct zoneent *ze; 8617c478bd9Sstevel@tonic-gate int res, err; 8627c478bd9Sstevel@tonic-gate FILE *cookie; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate cookie = setzoneent(); 8657c478bd9Sstevel@tonic-gate while ((ze = getzoneent_private(cookie)) != NULL) { 8667c478bd9Sstevel@tonic-gate /* Skip zones which are not installed. */ 8677c478bd9Sstevel@tonic-gate if (ze->zone_state < ZONE_STATE_INSTALLED) { 8687c478bd9Sstevel@tonic-gate free(ze); 8697c478bd9Sstevel@tonic-gate continue; 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate /* Skip the global zone and the current target zone. */ 8727c478bd9Sstevel@tonic-gate if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0 || 8737c478bd9Sstevel@tonic-gate strcmp(ze->zone_name, target_zone) == 0) { 8747c478bd9Sstevel@tonic-gate free(ze); 8757c478bd9Sstevel@tonic-gate continue; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate if (strlen(ze->zone_path) == 0) { 8787c478bd9Sstevel@tonic-gate /* old index file without path, fall back */ 8797c478bd9Sstevel@tonic-gate if ((err = zone_get_zonepath(ze->zone_name, 8807c478bd9Sstevel@tonic-gate ze->zone_path, sizeof (ze->zone_path))) != Z_OK) { 8817c478bd9Sstevel@tonic-gate errno = err; 8827c478bd9Sstevel@tonic-gate zperror2(ze->zone_name, 8837c478bd9Sstevel@tonic-gate gettext("could not get zone path")); 8847c478bd9Sstevel@tonic-gate free(ze); 8857c478bd9Sstevel@tonic-gate continue; 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate } 888108322fbScarlsonj (void) snprintf(path_copy, sizeof (path_copy), "%s%s", 889108322fbScarlsonj zonecfg_get_root(), ze->zone_path); 890108322fbScarlsonj res = resolvepath(path_copy, rpath, sizeof (rpath)); 8917c478bd9Sstevel@tonic-gate if (res == -1) { 8927c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 893108322fbScarlsonj zperror(path_copy, B_FALSE); 8947c478bd9Sstevel@tonic-gate free(ze); 8957c478bd9Sstevel@tonic-gate return (Z_ERR); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate (void) printf(gettext("WARNING: zone %s is installed, " 8987c478bd9Sstevel@tonic-gate "but its %s %s does not exist.\n"), ze->zone_name, 899108322fbScarlsonj "zonepath", path_copy); 9007c478bd9Sstevel@tonic-gate free(ze); 9017c478bd9Sstevel@tonic-gate continue; 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate rpath[res] = '\0'; 9047c478bd9Sstevel@tonic-gate (void) snprintf(path_copy, sizeof (path_copy), "%s/", path); 9057c478bd9Sstevel@tonic-gate (void) snprintf(rpath_copy, sizeof (rpath_copy), "%s/", rpath); 9067c478bd9Sstevel@tonic-gate if (strncmp(path_copy, rpath_copy, 9077c478bd9Sstevel@tonic-gate min(strlen(path_copy), strlen(rpath_copy))) == 0) { 9085ee84fbdSgjelinek /* 9095ee84fbdSgjelinek * TRANSLATION_NOTE 9105ee84fbdSgjelinek * zonepath is a literal that should not be translated. 9115ee84fbdSgjelinek */ 9127c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s zonepath (%s) and " 9137c478bd9Sstevel@tonic-gate "%s zonepath (%s) overlap.\n"), 9147c478bd9Sstevel@tonic-gate target_zone, path, ze->zone_name, rpath); 9157c478bd9Sstevel@tonic-gate free(ze); 9167c478bd9Sstevel@tonic-gate return (Z_ERR); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate free(ze); 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate endzoneent(cookie); 9217c478bd9Sstevel@tonic-gate return (Z_OK); 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate static int 9257c478bd9Sstevel@tonic-gate validate_zonepath(char *path, int cmd_num) 9267c478bd9Sstevel@tonic-gate { 9277c478bd9Sstevel@tonic-gate int res; /* result of last library/system call */ 9287c478bd9Sstevel@tonic-gate boolean_t err = B_FALSE; /* have we run into an error? */ 9297c478bd9Sstevel@tonic-gate struct stat stbuf; 9303f2f09c1Sdp struct statvfs64 vfsbuf; 9317c478bd9Sstevel@tonic-gate char rpath[MAXPATHLEN]; /* resolved path */ 9327c478bd9Sstevel@tonic-gate char ppath[MAXPATHLEN]; /* parent path */ 9337c478bd9Sstevel@tonic-gate char rppath[MAXPATHLEN]; /* resolved parent path */ 9347c478bd9Sstevel@tonic-gate char rootpath[MAXPATHLEN]; /* root path */ 9357c478bd9Sstevel@tonic-gate zone_state_t state; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate if (path[0] != '/') { 9387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 9397c478bd9Sstevel@tonic-gate gettext("%s is not an absolute path.\n"), path); 9407c478bd9Sstevel@tonic-gate return (Z_ERR); 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate if ((res = resolvepath(path, rpath, sizeof (rpath))) == -1) { 9437c478bd9Sstevel@tonic-gate if ((errno != ENOENT) || 944865e09a4Sgjelinek (cmd_num != CMD_VERIFY && cmd_num != CMD_INSTALL && 945865e09a4Sgjelinek cmd_num != CMD_CLONE && cmd_num != CMD_MOVE)) { 9467c478bd9Sstevel@tonic-gate zperror(path, B_FALSE); 9477c478bd9Sstevel@tonic-gate return (Z_ERR); 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate if (cmd_num == CMD_VERIFY) { 9505ee84fbdSgjelinek /* 9515ee84fbdSgjelinek * TRANSLATION_NOTE 9525ee84fbdSgjelinek * zoneadm is a literal that should not be translated. 9535ee84fbdSgjelinek */ 9547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("WARNING: %s does not " 9555ee84fbdSgjelinek "exist, so it could not be verified.\nWhen " 9565ee84fbdSgjelinek "'zoneadm %s' is run, '%s' will try to create\n%s, " 9575ee84fbdSgjelinek "and '%s' will be tried again,\nbut the '%s' may " 9585ee84fbdSgjelinek "fail if:\nthe parent directory of %s is group- or " 9595ee84fbdSgjelinek "other-writable\nor\n%s overlaps with any other " 9607c478bd9Sstevel@tonic-gate "installed zones.\n"), path, 9617c478bd9Sstevel@tonic-gate cmd_to_str(CMD_INSTALL), cmd_to_str(CMD_INSTALL), 9627c478bd9Sstevel@tonic-gate path, cmd_to_str(CMD_VERIFY), 9637c478bd9Sstevel@tonic-gate cmd_to_str(CMD_VERIFY), path, path); 9647c478bd9Sstevel@tonic-gate return (Z_OK); 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate /* 9677c478bd9Sstevel@tonic-gate * The zonepath is supposed to be mode 700 but its 9687c478bd9Sstevel@tonic-gate * parent(s) 755. So use 755 on the mkdirp() then 9697c478bd9Sstevel@tonic-gate * chmod() the zonepath itself to 700. 9707c478bd9Sstevel@tonic-gate */ 9717c478bd9Sstevel@tonic-gate if (mkdirp(path, DEFAULT_DIR_MODE) < 0) { 9727c478bd9Sstevel@tonic-gate zperror(path, B_FALSE); 9737c478bd9Sstevel@tonic-gate return (Z_ERR); 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate /* 9767c478bd9Sstevel@tonic-gate * If the chmod() fails, report the error, but might 9777c478bd9Sstevel@tonic-gate * as well continue the verify procedure. 9787c478bd9Sstevel@tonic-gate */ 9797c478bd9Sstevel@tonic-gate if (chmod(path, S_IRWXU) != 0) 9807c478bd9Sstevel@tonic-gate zperror(path, B_FALSE); 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * Since the mkdir() succeeded, we should not have to 9837c478bd9Sstevel@tonic-gate * worry about a subsequent ENOENT, thus this should 9847c478bd9Sstevel@tonic-gate * only recurse once. 9857c478bd9Sstevel@tonic-gate */ 986865e09a4Sgjelinek return (validate_zonepath(path, cmd_num)); 9877c478bd9Sstevel@tonic-gate } 9887c478bd9Sstevel@tonic-gate rpath[res] = '\0'; 9897c478bd9Sstevel@tonic-gate if (strcmp(path, rpath) != 0) { 9907c478bd9Sstevel@tonic-gate errno = Z_RESOLVED_PATH; 9917c478bd9Sstevel@tonic-gate zperror(path, B_TRUE); 9927c478bd9Sstevel@tonic-gate return (Z_ERR); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate if ((res = stat(rpath, &stbuf)) != 0) { 9957c478bd9Sstevel@tonic-gate zperror(rpath, B_FALSE); 9967c478bd9Sstevel@tonic-gate return (Z_ERR); 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate if (!S_ISDIR(stbuf.st_mode)) { 9997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not a directory.\n"), 10007c478bd9Sstevel@tonic-gate rpath); 10017c478bd9Sstevel@tonic-gate return (Z_ERR); 10027c478bd9Sstevel@tonic-gate } 10034fceebdfSblakej if (strcmp(stbuf.st_fstype, MNTTYPE_TMPFS) == 0) { 10047c478bd9Sstevel@tonic-gate (void) printf(gettext("WARNING: %s is on a temporary " 10050b5de56dSgjelinek "file system.\n"), rpath); 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate if (crosscheck_zonepaths(rpath) != Z_OK) 10087c478bd9Sstevel@tonic-gate return (Z_ERR); 10097c478bd9Sstevel@tonic-gate /* 10107c478bd9Sstevel@tonic-gate * Try to collect and report as many minor errors as possible 10117c478bd9Sstevel@tonic-gate * before returning, so the user can learn everything that needs 10127c478bd9Sstevel@tonic-gate * to be fixed up front. 10137c478bd9Sstevel@tonic-gate */ 10147c478bd9Sstevel@tonic-gate if (stbuf.st_uid != 0) { 10157c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not owned by root.\n"), 10167c478bd9Sstevel@tonic-gate rpath); 10177c478bd9Sstevel@tonic-gate err = B_TRUE; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rpath); 10207c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rpath); 10217c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rpath); 10227c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IRGRP, B_FALSE, rpath); 10237c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rpath); 10247c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IXGRP, B_FALSE, rpath); 10257c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IROTH, B_FALSE, rpath); 10267c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rpath); 10277c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IXOTH, B_FALSE, rpath); 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate (void) snprintf(ppath, sizeof (ppath), "%s/..", path); 10307c478bd9Sstevel@tonic-gate if ((res = resolvepath(ppath, rppath, sizeof (rppath))) == -1) { 10317c478bd9Sstevel@tonic-gate zperror(ppath, B_FALSE); 10327c478bd9Sstevel@tonic-gate return (Z_ERR); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate rppath[res] = '\0'; 10357c478bd9Sstevel@tonic-gate if ((res = stat(rppath, &stbuf)) != 0) { 10367c478bd9Sstevel@tonic-gate zperror(rppath, B_FALSE); 10377c478bd9Sstevel@tonic-gate return (Z_ERR); 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate /* theoretically impossible */ 10407c478bd9Sstevel@tonic-gate if (!S_ISDIR(stbuf.st_mode)) { 10417c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not a directory.\n"), 10427c478bd9Sstevel@tonic-gate rppath); 10437c478bd9Sstevel@tonic-gate return (Z_ERR); 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate if (stbuf.st_uid != 0) { 10467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not owned by root.\n"), 10477c478bd9Sstevel@tonic-gate rppath); 10487c478bd9Sstevel@tonic-gate err = B_TRUE; 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rppath); 10517c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rppath); 10527c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rppath); 10537c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rppath); 10547c478bd9Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rppath); 10557c478bd9Sstevel@tonic-gate if (strcmp(rpath, rppath) == 0) { 10567c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is its own parent.\n"), 10577c478bd9Sstevel@tonic-gate rppath); 10587c478bd9Sstevel@tonic-gate err = B_TRUE; 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate 10613f2f09c1Sdp if (statvfs64(rpath, &vfsbuf) != 0) { 10627c478bd9Sstevel@tonic-gate zperror(rpath, B_FALSE); 10637c478bd9Sstevel@tonic-gate return (Z_ERR); 10647c478bd9Sstevel@tonic-gate } 1065b5abaf04Sgjelinek if (strcmp(vfsbuf.f_basetype, MNTTYPE_NFS) == 0) { 10665ee84fbdSgjelinek /* 10675ee84fbdSgjelinek * TRANSLATION_NOTE 10685ee84fbdSgjelinek * Zonepath and NFS are literals that should not be translated. 10695ee84fbdSgjelinek */ 10705ee84fbdSgjelinek (void) fprintf(stderr, gettext("Zonepath %s is on an NFS " 10710b5de56dSgjelinek "mounted file system.\n" 10720b5de56dSgjelinek "\tA local file system must be used.\n"), rpath); 1073b5abaf04Sgjelinek return (Z_ERR); 1074b5abaf04Sgjelinek } 1075b5abaf04Sgjelinek if (vfsbuf.f_flag & ST_NOSUID) { 10765ee84fbdSgjelinek /* 10775ee84fbdSgjelinek * TRANSLATION_NOTE 10785ee84fbdSgjelinek * Zonepath and nosuid are literals that should not be 10795ee84fbdSgjelinek * translated. 10805ee84fbdSgjelinek */ 1081b5abaf04Sgjelinek (void) fprintf(stderr, gettext("Zonepath %s is on a nosuid " 10820b5de56dSgjelinek "file system.\n"), rpath); 10837c478bd9Sstevel@tonic-gate return (Z_ERR); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate if ((res = zone_get_state(target_zone, &state)) != Z_OK) { 10877c478bd9Sstevel@tonic-gate errno = res; 10887c478bd9Sstevel@tonic-gate zperror2(target_zone, gettext("could not get state")); 10897c478bd9Sstevel@tonic-gate return (Z_ERR); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate /* 10927c478bd9Sstevel@tonic-gate * The existence of the root path is only bad in the configured state, 10937c478bd9Sstevel@tonic-gate * as it is *supposed* to be there at the installed and later states. 1094ee519a1fSgjelinek * However, the root path is expected to be there if the zone is 1095ee519a1fSgjelinek * detached. 10967c478bd9Sstevel@tonic-gate * State/command mismatches are caught earlier in verify_details(). 10977c478bd9Sstevel@tonic-gate */ 1098ee519a1fSgjelinek if (state == ZONE_STATE_CONFIGURED && cmd_num != CMD_ATTACH) { 10997c478bd9Sstevel@tonic-gate if (snprintf(rootpath, sizeof (rootpath), "%s/root", rpath) >= 11007c478bd9Sstevel@tonic-gate sizeof (rootpath)) { 11015ee84fbdSgjelinek /* 11025ee84fbdSgjelinek * TRANSLATION_NOTE 11035ee84fbdSgjelinek * Zonepath is a literal that should not be translated. 11045ee84fbdSgjelinek */ 11057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 11067c478bd9Sstevel@tonic-gate gettext("Zonepath %s is too long.\n"), rpath); 11077c478bd9Sstevel@tonic-gate return (Z_ERR); 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate if ((res = stat(rootpath, &stbuf)) == 0) { 1110c4a45622S if (zonecfg_detached(rpath)) { 1111ee519a1fSgjelinek (void) fprintf(stderr, 1112ee519a1fSgjelinek gettext("Cannot %s detached " 1113ee519a1fSgjelinek "zone.\nUse attach or remove %s " 1114ee519a1fSgjelinek "directory.\n"), cmd_to_str(cmd_num), 1115ee519a1fSgjelinek rpath); 11167c478bd9Sstevel@tonic-gate return (Z_ERR); 11177c478bd9Sstevel@tonic-gate } 1118c4a45622S 1119c4a45622S /* Not detached, check if it really looks ok. */ 1120c4a45622S 1121c4a45622S if (!S_ISDIR(stbuf.st_mode)) { 1122c4a45622S (void) fprintf(stderr, gettext("%s is not a " 1123c4a45622S "directory.\n"), rootpath); 1124c4a45622S return (Z_ERR); 1125c4a45622S } 1126c4a45622S 1127c4a45622S if (stbuf.st_uid != 0) { 1128c4a45622S (void) fprintf(stderr, gettext("%s is not " 1129c4a45622S "owned by root.\n"), rootpath); 1130c4a45622S return (Z_ERR); 1131c4a45622S } 1132c4a45622S 1133c4a45622S if ((stbuf.st_mode & 0777) != 0755) { 1134c4a45622S (void) fprintf(stderr, gettext("%s mode is not " 1135c4a45622S "0755.\n"), rootpath); 1136c4a45622S return (Z_ERR); 1137c4a45622S } 1138c4a45622S } 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate return (err ? Z_ERR : Z_OK); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate static int 1145ce28b40eSzt129084 invoke_brand_handler(int cmd_num, char *argv[]) 1146ce28b40eSzt129084 { 1147ce28b40eSzt129084 zone_dochandle_t handle; 1148ce28b40eSzt129084 int err; 1149ce28b40eSzt129084 1150ce28b40eSzt129084 if ((handle = zonecfg_init_handle()) == NULL) { 1151ce28b40eSzt129084 zperror(cmd_to_str(cmd_num), B_TRUE); 1152ce28b40eSzt129084 return (Z_ERR); 1153ce28b40eSzt129084 } 1154ce28b40eSzt129084 if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 1155ce28b40eSzt129084 errno = err; 1156ce28b40eSzt129084 zperror(cmd_to_str(cmd_num), B_TRUE); 1157ce28b40eSzt129084 zonecfg_fini_handle(handle); 1158ce28b40eSzt129084 return (Z_ERR); 1159ce28b40eSzt129084 } 1160ce28b40eSzt129084 if (verify_brand(handle, cmd_num, argv) != Z_OK) { 1161ce28b40eSzt129084 zonecfg_fini_handle(handle); 1162ce28b40eSzt129084 return (Z_ERR); 1163ce28b40eSzt129084 } 1164ce28b40eSzt129084 zonecfg_fini_handle(handle); 1165ce28b40eSzt129084 return (Z_OK); 1166ce28b40eSzt129084 } 1167ce28b40eSzt129084 1168ce28b40eSzt129084 static int 11697c478bd9Sstevel@tonic-gate ready_func(int argc, char *argv[]) 11707c478bd9Sstevel@tonic-gate { 11717c478bd9Sstevel@tonic-gate zone_cmd_arg_t zarg; 11727c478bd9Sstevel@tonic-gate int arg; 11737c478bd9Sstevel@tonic-gate 1174108322fbScarlsonj if (zonecfg_in_alt_root()) { 1175108322fbScarlsonj zerror(gettext("cannot ready zone in alternate root")); 1176108322fbScarlsonj return (Z_ERR); 1177108322fbScarlsonj } 1178108322fbScarlsonj 11797c478bd9Sstevel@tonic-gate optind = 0; 11807c478bd9Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 11817c478bd9Sstevel@tonic-gate switch (arg) { 11827c478bd9Sstevel@tonic-gate case '?': 11837c478bd9Sstevel@tonic-gate sub_usage(SHELP_READY, CMD_READY); 11847c478bd9Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 11857c478bd9Sstevel@tonic-gate default: 11867c478bd9Sstevel@tonic-gate sub_usage(SHELP_READY, CMD_READY); 11877c478bd9Sstevel@tonic-gate return (Z_USAGE); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate if (argc > optind) { 11917c478bd9Sstevel@tonic-gate sub_usage(SHELP_READY, CMD_READY); 11927c478bd9Sstevel@tonic-gate return (Z_USAGE); 11937c478bd9Sstevel@tonic-gate } 11949acbbeafSnn35248 if (sanity_check(target_zone, CMD_READY, B_FALSE, B_FALSE, B_FALSE) 11959acbbeafSnn35248 != Z_OK) 11967c478bd9Sstevel@tonic-gate return (Z_ERR); 1197ce28b40eSzt129084 if (verify_details(CMD_READY, argv) != Z_OK) 11987c478bd9Sstevel@tonic-gate return (Z_ERR); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate zarg.cmd = Z_READY; 1201ff17c8bfSgjelinek if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) { 12027c478bd9Sstevel@tonic-gate zerror(gettext("call to %s failed"), "zoneadmd"); 12037c478bd9Sstevel@tonic-gate return (Z_ERR); 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate return (Z_OK); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate static int 12097c478bd9Sstevel@tonic-gate boot_func(int argc, char *argv[]) 12107c478bd9Sstevel@tonic-gate { 12117c478bd9Sstevel@tonic-gate zone_cmd_arg_t zarg; 12129acbbeafSnn35248 boolean_t force = B_FALSE; 12137c478bd9Sstevel@tonic-gate int arg; 12147c478bd9Sstevel@tonic-gate 1215108322fbScarlsonj if (zonecfg_in_alt_root()) { 1216108322fbScarlsonj zerror(gettext("cannot boot zone in alternate root")); 1217108322fbScarlsonj return (Z_ERR); 1218108322fbScarlsonj } 1219108322fbScarlsonj 12207c478bd9Sstevel@tonic-gate zarg.bootbuf[0] = '\0'; 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate /* 12233f2f09c1Sdp * The following getopt processes arguments to zone boot; that 12243f2f09c1Sdp * is to say, the [here] portion of the argument string: 12253f2f09c1Sdp * 12263f2f09c1Sdp * zoneadm -z myzone boot [here] -- -v -m verbose 12273f2f09c1Sdp * 12283f2f09c1Sdp * Where [here] can either be nothing, -? (in which case we bail 12299acbbeafSnn35248 * and print usage), -f (a private option to indicate that the 12309acbbeafSnn35248 * boot operation should be 'forced'), or -s. Support for -s is 12319acbbeafSnn35248 * vestigal and obsolete, but is retained because it was a 12329acbbeafSnn35248 * documented interface and there are known consumers including 12339acbbeafSnn35248 * admin/install; the proper way to specify boot arguments like -s 12349acbbeafSnn35248 * is: 12353f2f09c1Sdp * 12363f2f09c1Sdp * zoneadm -z myzone boot -- -s -v -m verbose. 12377c478bd9Sstevel@tonic-gate */ 12387c478bd9Sstevel@tonic-gate optind = 0; 12399acbbeafSnn35248 while ((arg = getopt(argc, argv, "?fs")) != EOF) { 12407c478bd9Sstevel@tonic-gate switch (arg) { 12417c478bd9Sstevel@tonic-gate case '?': 12427c478bd9Sstevel@tonic-gate sub_usage(SHELP_BOOT, CMD_BOOT); 12437c478bd9Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 12447c478bd9Sstevel@tonic-gate case 's': 12457c478bd9Sstevel@tonic-gate (void) strlcpy(zarg.bootbuf, "-s", 12467c478bd9Sstevel@tonic-gate sizeof (zarg.bootbuf)); 12477c478bd9Sstevel@tonic-gate break; 12489acbbeafSnn35248 case 'f': 12499acbbeafSnn35248 force = B_TRUE; 12509acbbeafSnn35248 break; 12517c478bd9Sstevel@tonic-gate default: 12527c478bd9Sstevel@tonic-gate sub_usage(SHELP_BOOT, CMD_BOOT); 12537c478bd9Sstevel@tonic-gate return (Z_USAGE); 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate } 12563f2f09c1Sdp 12573f2f09c1Sdp for (; optind < argc; optind++) { 12583f2f09c1Sdp if (strlcat(zarg.bootbuf, argv[optind], 12593f2f09c1Sdp sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) { 12603f2f09c1Sdp zerror(gettext("Boot argument list too long")); 12613f2f09c1Sdp return (Z_ERR); 12627c478bd9Sstevel@tonic-gate } 12633f2f09c1Sdp if (optind < argc - 1) 12643f2f09c1Sdp if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >= 12653f2f09c1Sdp sizeof (zarg.bootbuf)) { 12663f2f09c1Sdp zerror(gettext("Boot argument list too long")); 12673f2f09c1Sdp return (Z_ERR); 12683f2f09c1Sdp } 12693f2f09c1Sdp } 12709acbbeafSnn35248 if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE, force) 12719acbbeafSnn35248 != Z_OK) 12727c478bd9Sstevel@tonic-gate return (Z_ERR); 1273ce28b40eSzt129084 if (verify_details(CMD_BOOT, argv) != Z_OK) 12747c478bd9Sstevel@tonic-gate return (Z_ERR); 12759acbbeafSnn35248 zarg.cmd = force ? Z_FORCEBOOT : Z_BOOT; 1276ff17c8bfSgjelinek if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) { 12777c478bd9Sstevel@tonic-gate zerror(gettext("call to %s failed"), "zoneadmd"); 12787c478bd9Sstevel@tonic-gate return (Z_ERR); 12797c478bd9Sstevel@tonic-gate } 12800209230bSgjelinek 12817c478bd9Sstevel@tonic-gate return (Z_OK); 12827c478bd9Sstevel@tonic-gate } 12837c478bd9Sstevel@tonic-gate 12847c478bd9Sstevel@tonic-gate static void 12857c478bd9Sstevel@tonic-gate fake_up_local_zone(zoneid_t zid, zone_entry_t *zeptr) 12867c478bd9Sstevel@tonic-gate { 12877c478bd9Sstevel@tonic-gate ssize_t result; 1288555afedfScarlsonj uuid_t uuid; 1289555afedfScarlsonj FILE *fp; 1290f4b3ec61Sdh155122 ushort_t flags; 1291555afedfScarlsonj 1292555afedfScarlsonj (void) memset(zeptr, 0, sizeof (*zeptr)); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate zeptr->zid = zid; 1295555afedfScarlsonj 12967c478bd9Sstevel@tonic-gate /* 12977c478bd9Sstevel@tonic-gate * Since we're looking up our own (non-global) zone name, 12987c478bd9Sstevel@tonic-gate * we can be assured that it will succeed. 12997c478bd9Sstevel@tonic-gate */ 13007c478bd9Sstevel@tonic-gate result = getzonenamebyid(zid, zeptr->zname, sizeof (zeptr->zname)); 13017c478bd9Sstevel@tonic-gate assert(result >= 0); 1302555afedfScarlsonj if (zonecfg_is_scratch(zeptr->zname) && 1303555afedfScarlsonj (fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 1304555afedfScarlsonj (void) zonecfg_reverse_scratch(fp, zeptr->zname, zeptr->zname, 1305555afedfScarlsonj sizeof (zeptr->zname), NULL, 0); 1306555afedfScarlsonj zonecfg_close_scratch(fp); 1307555afedfScarlsonj } 1308555afedfScarlsonj 1309555afedfScarlsonj if (is_system_labeled()) { 131045916cd2Sjpk (void) zone_getattr(zid, ZONE_ATTR_ROOT, zeptr->zroot, 131145916cd2Sjpk sizeof (zeptr->zroot)); 13129acbbeafSnn35248 (void) strlcpy(zeptr->zbrand, NATIVE_BRAND_NAME, 13139acbbeafSnn35248 sizeof (zeptr->zbrand)); 1314555afedfScarlsonj } else { 1315555afedfScarlsonj (void) strlcpy(zeptr->zroot, "/", sizeof (zeptr->zroot)); 13169acbbeafSnn35248 (void) zone_getattr(zid, ZONE_ATTR_BRAND, zeptr->zbrand, 13179acbbeafSnn35248 sizeof (zeptr->zbrand)); 131845916cd2Sjpk } 1319555afedfScarlsonj 13207c478bd9Sstevel@tonic-gate zeptr->zstate_str = "running"; 1321555afedfScarlsonj if (zonecfg_get_uuid(zeptr->zname, uuid) == Z_OK && 1322555afedfScarlsonj !uuid_is_null(uuid)) 1323555afedfScarlsonj uuid_unparse(uuid, zeptr->zuuid); 1324f4b3ec61Sdh155122 1325f4b3ec61Sdh155122 if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags, sizeof (flags)) < 0) { 1326f4b3ec61Sdh155122 zperror2(zeptr->zname, gettext("could not get zone flags")); 1327f4b3ec61Sdh155122 exit(Z_ERR); 1328f4b3ec61Sdh155122 } 1329f4b3ec61Sdh155122 if (flags & ZF_NET_EXCL) 1330f4b3ec61Sdh155122 zeptr->ziptype = ZS_EXCLUSIVE; 1331f4b3ec61Sdh155122 else 1332f4b3ec61Sdh155122 zeptr->ziptype = ZS_SHARED; 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate static int 13367c478bd9Sstevel@tonic-gate list_func(int argc, char *argv[]) 13377c478bd9Sstevel@tonic-gate { 13387c478bd9Sstevel@tonic-gate zone_entry_t *zentp, zent; 1339108322fbScarlsonj int arg, retv; 13407c478bd9Sstevel@tonic-gate boolean_t output = B_FALSE, verbose = B_FALSE, parsable = B_FALSE; 13417c478bd9Sstevel@tonic-gate zone_state_t min_state = ZONE_STATE_RUNNING; 13427c478bd9Sstevel@tonic-gate zoneid_t zone_id = getzoneid(); 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate if (target_zone == NULL) { 13457c478bd9Sstevel@tonic-gate /* all zones: default view to running but allow override */ 13467c478bd9Sstevel@tonic-gate optind = 0; 13477c478bd9Sstevel@tonic-gate while ((arg = getopt(argc, argv, "?cipv")) != EOF) { 13487c478bd9Sstevel@tonic-gate switch (arg) { 13497c478bd9Sstevel@tonic-gate case '?': 13507c478bd9Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 13517c478bd9Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 1352475d78a4Sjonb /* 1353475d78a4Sjonb * The 'i' and 'c' options are not mutually 1354475d78a4Sjonb * exclusive so if 'c' is given, then min_state 1355475d78a4Sjonb * is set to 0 (ZONE_STATE_CONFIGURED) which is 1356475d78a4Sjonb * the lowest possible state. If 'i' is given, 1357475d78a4Sjonb * then min_state is set to be the lowest state 1358475d78a4Sjonb * so far. 1359475d78a4Sjonb */ 13607c478bd9Sstevel@tonic-gate case 'c': 13617c478bd9Sstevel@tonic-gate min_state = ZONE_STATE_CONFIGURED; 13627c478bd9Sstevel@tonic-gate break; 13637c478bd9Sstevel@tonic-gate case 'i': 1364475d78a4Sjonb min_state = min(ZONE_STATE_INSTALLED, 1365475d78a4Sjonb min_state); 1366475d78a4Sjonb 13677c478bd9Sstevel@tonic-gate break; 13687c478bd9Sstevel@tonic-gate case 'p': 13697c478bd9Sstevel@tonic-gate parsable = B_TRUE; 13707c478bd9Sstevel@tonic-gate break; 13717c478bd9Sstevel@tonic-gate case 'v': 13727c478bd9Sstevel@tonic-gate verbose = B_TRUE; 13737c478bd9Sstevel@tonic-gate break; 13747c478bd9Sstevel@tonic-gate default: 13757c478bd9Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 13767c478bd9Sstevel@tonic-gate return (Z_USAGE); 13777c478bd9Sstevel@tonic-gate } 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate if (parsable && verbose) { 13807c478bd9Sstevel@tonic-gate zerror(gettext("%s -p and -v are mutually exclusive."), 13817c478bd9Sstevel@tonic-gate cmd_to_str(CMD_LIST)); 13827c478bd9Sstevel@tonic-gate return (Z_ERR); 13837c478bd9Sstevel@tonic-gate } 138445916cd2Sjpk if (zone_id == GLOBAL_ZONEID || is_system_labeled()) { 1385108322fbScarlsonj retv = zone_print_list(min_state, verbose, parsable); 13867c478bd9Sstevel@tonic-gate } else { 13877c478bd9Sstevel@tonic-gate fake_up_local_zone(zone_id, &zent); 13889acbbeafSnn35248 retv = Z_OK; 13897c478bd9Sstevel@tonic-gate zone_print(&zent, verbose, parsable); 13907c478bd9Sstevel@tonic-gate } 1391108322fbScarlsonj return (retv); 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * Specific target zone: disallow -i/-c suboptions. 13967c478bd9Sstevel@tonic-gate */ 13977c478bd9Sstevel@tonic-gate optind = 0; 13987c478bd9Sstevel@tonic-gate while ((arg = getopt(argc, argv, "?pv")) != EOF) { 13997c478bd9Sstevel@tonic-gate switch (arg) { 14007c478bd9Sstevel@tonic-gate case '?': 14017c478bd9Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 14027c478bd9Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 14037c478bd9Sstevel@tonic-gate case 'p': 14047c478bd9Sstevel@tonic-gate parsable = B_TRUE; 14057c478bd9Sstevel@tonic-gate break; 14067c478bd9Sstevel@tonic-gate case 'v': 14077c478bd9Sstevel@tonic-gate verbose = B_TRUE; 14087c478bd9Sstevel@tonic-gate break; 14097c478bd9Sstevel@tonic-gate default: 14107c478bd9Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 14117c478bd9Sstevel@tonic-gate return (Z_USAGE); 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate } 14147c478bd9Sstevel@tonic-gate if (parsable && verbose) { 14157c478bd9Sstevel@tonic-gate zerror(gettext("%s -p and -v are mutually exclusive."), 14167c478bd9Sstevel@tonic-gate cmd_to_str(CMD_LIST)); 14177c478bd9Sstevel@tonic-gate return (Z_ERR); 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate if (argc > optind) { 14207c478bd9Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 14217c478bd9Sstevel@tonic-gate return (Z_USAGE); 14227c478bd9Sstevel@tonic-gate } 14232ec67e04Sgjelinek if (zone_id != GLOBAL_ZONEID && !is_system_labeled()) { 14247c478bd9Sstevel@tonic-gate fake_up_local_zone(zone_id, &zent); 14257c478bd9Sstevel@tonic-gate /* 14267c478bd9Sstevel@tonic-gate * main() will issue a Z_NO_ZONE error if it cannot get an 14277c478bd9Sstevel@tonic-gate * id for target_zone, which in a non-global zone should 14287c478bd9Sstevel@tonic-gate * happen for any zone name except `zonename`. Thus we 14297c478bd9Sstevel@tonic-gate * assert() that here but don't otherwise check. 14307c478bd9Sstevel@tonic-gate */ 14317c478bd9Sstevel@tonic-gate assert(strcmp(zent.zname, target_zone) == 0); 14327c478bd9Sstevel@tonic-gate zone_print(&zent, verbose, parsable); 14337c478bd9Sstevel@tonic-gate output = B_TRUE; 14347c478bd9Sstevel@tonic-gate } else if ((zentp = lookup_running_zone(target_zone)) != NULL) { 14357c478bd9Sstevel@tonic-gate zone_print(zentp, verbose, parsable); 14367c478bd9Sstevel@tonic-gate output = B_TRUE; 1437108322fbScarlsonj } else if (lookup_zone_info(target_zone, ZONE_ID_UNDEFINED, 1438108322fbScarlsonj &zent) == Z_OK) { 14397c478bd9Sstevel@tonic-gate zone_print(&zent, verbose, parsable); 14407c478bd9Sstevel@tonic-gate output = B_TRUE; 14417c478bd9Sstevel@tonic-gate } 1442ce28b40eSzt129084 1443ce28b40eSzt129084 /* 1444ce28b40eSzt129084 * Invoke brand-specific handler. Note that we do this 1445db628066Sgjelinek * only if we're in the global zone, and target_zone is specified 1446db628066Sgjelinek * and it is not the global zone. 1447ce28b40eSzt129084 */ 1448db628066Sgjelinek if (zone_id == GLOBAL_ZONEID && target_zone != NULL && 1449db628066Sgjelinek strcmp(target_zone, GLOBAL_ZONENAME) != 0) 1450ce28b40eSzt129084 if (invoke_brand_handler(CMD_LIST, argv) != Z_OK) 1451ce28b40eSzt129084 return (Z_ERR); 1452ce28b40eSzt129084 14537c478bd9Sstevel@tonic-gate return (output ? Z_OK : Z_ERR); 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 1456ff17c8bfSgjelinek int 1457c75cc341S do_subproc(char *cmdbuf) 14589acbbeafSnn35248 { 14599acbbeafSnn35248 void (*saveint)(int); 14609acbbeafSnn35248 void (*saveterm)(int); 14619acbbeafSnn35248 void (*savequit)(int); 14629acbbeafSnn35248 void (*savehup)(int); 14639acbbeafSnn35248 int pid, child, status; 14649acbbeafSnn35248 14659acbbeafSnn35248 if ((child = vfork()) == 0) { 14669acbbeafSnn35248 (void) execl("/bin/sh", "sh", "-c", cmdbuf, (char *)NULL); 14679acbbeafSnn35248 } 14689acbbeafSnn35248 14699acbbeafSnn35248 if (child == -1) 14709acbbeafSnn35248 return (-1); 14719acbbeafSnn35248 14729acbbeafSnn35248 saveint = sigset(SIGINT, SIG_IGN); 14739acbbeafSnn35248 saveterm = sigset(SIGTERM, SIG_IGN); 14749acbbeafSnn35248 savequit = sigset(SIGQUIT, SIG_IGN); 14759acbbeafSnn35248 savehup = sigset(SIGHUP, SIG_IGN); 14769acbbeafSnn35248 14779acbbeafSnn35248 while ((pid = waitpid(child, &status, 0)) != child && pid != -1) 14789acbbeafSnn35248 ; 14799acbbeafSnn35248 14809acbbeafSnn35248 (void) sigset(SIGINT, saveint); 14819acbbeafSnn35248 (void) sigset(SIGTERM, saveterm); 14829acbbeafSnn35248 (void) sigset(SIGQUIT, savequit); 14839acbbeafSnn35248 (void) sigset(SIGHUP, savehup); 14849acbbeafSnn35248 14859acbbeafSnn35248 return (pid == -1 ? -1 : status); 14869acbbeafSnn35248 } 14879acbbeafSnn35248 1488ff17c8bfSgjelinek int 14899acbbeafSnn35248 subproc_status(const char *cmd, int status, boolean_t verbose_failure) 14907c478bd9Sstevel@tonic-gate { 14917c478bd9Sstevel@tonic-gate if (WIFEXITED(status)) { 14927c478bd9Sstevel@tonic-gate int exit_code = WEXITSTATUS(status); 14937c478bd9Sstevel@tonic-gate 14949acbbeafSnn35248 if ((verbose_failure) && (exit_code != ZONE_SUBPROC_OK)) 14957c478bd9Sstevel@tonic-gate zerror(gettext("'%s' failed with exit code %d."), cmd, 14967c478bd9Sstevel@tonic-gate exit_code); 14979acbbeafSnn35248 14989acbbeafSnn35248 return (exit_code); 14997c478bd9Sstevel@tonic-gate } else if (WIFSIGNALED(status)) { 15007c478bd9Sstevel@tonic-gate int signal = WTERMSIG(status); 15017c478bd9Sstevel@tonic-gate char sigstr[SIG2STR_MAX]; 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate if (sig2str(signal, sigstr) == 0) { 15047c478bd9Sstevel@tonic-gate zerror(gettext("'%s' terminated by signal SIG%s."), cmd, 15057c478bd9Sstevel@tonic-gate sigstr); 15067c478bd9Sstevel@tonic-gate } else { 15077c478bd9Sstevel@tonic-gate zerror(gettext("'%s' terminated by an unknown signal."), 15087c478bd9Sstevel@tonic-gate cmd); 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate } else { 15117c478bd9Sstevel@tonic-gate zerror(gettext("'%s' failed for unknown reasons."), cmd); 15127c478bd9Sstevel@tonic-gate } 15139acbbeafSnn35248 15149acbbeafSnn35248 /* 15159acbbeafSnn35248 * Assume a subprocess that died due to a signal or an unknown error 15169acbbeafSnn35248 * should be considered an exit code of ZONE_SUBPROC_FATAL, as the 15179acbbeafSnn35248 * user will likely need to do some manual cleanup. 15189acbbeafSnn35248 */ 15199acbbeafSnn35248 return (ZONE_SUBPROC_FATAL); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate 1522cb8a054bSGlenn Faden static int 1523cb8a054bSGlenn Faden auth_check(char *user, char *zone, int cmd_num) 1524cb8a054bSGlenn Faden { 1525cb8a054bSGlenn Faden char authname[MAXAUTHS]; 1526cb8a054bSGlenn Faden 1527cb8a054bSGlenn Faden switch (cmd_num) { 1528cb8a054bSGlenn Faden case CMD_LIST: 1529cb8a054bSGlenn Faden case CMD_HELP: 1530cb8a054bSGlenn Faden return (Z_OK); 1531cb8a054bSGlenn Faden case SOURCE_ZONE: 1532cb8a054bSGlenn Faden (void) strlcpy(authname, ZONE_CLONEFROM_AUTH, MAXAUTHS); 1533cb8a054bSGlenn Faden break; 1534cb8a054bSGlenn Faden case CMD_BOOT: 1535cb8a054bSGlenn Faden case CMD_HALT: 1536cb8a054bSGlenn Faden case CMD_READY: 1537cb8a054bSGlenn Faden case CMD_REBOOT: 1538cb8a054bSGlenn Faden case CMD_SYSBOOT: 1539cb8a054bSGlenn Faden case CMD_VERIFY: 1540cb8a054bSGlenn Faden case CMD_INSTALL: 1541cb8a054bSGlenn Faden case CMD_UNINSTALL: 1542cb8a054bSGlenn Faden case CMD_MOUNT: 1543cb8a054bSGlenn Faden case CMD_UNMOUNT: 1544cb8a054bSGlenn Faden case CMD_CLONE: 1545cb8a054bSGlenn Faden case CMD_MOVE: 1546cb8a054bSGlenn Faden case CMD_DETACH: 1547cb8a054bSGlenn Faden case CMD_ATTACH: 1548cb8a054bSGlenn Faden case CMD_MARK: 1549cb8a054bSGlenn Faden case CMD_APPLY: 1550cb8a054bSGlenn Faden default: 1551cb8a054bSGlenn Faden (void) strlcpy(authname, ZONE_MANAGE_AUTH, MAXAUTHS); 1552cb8a054bSGlenn Faden break; 1553cb8a054bSGlenn Faden } 1554cb8a054bSGlenn Faden (void) strlcat(authname, KV_OBJECT, MAXAUTHS); 1555cb8a054bSGlenn Faden (void) strlcat(authname, zone, MAXAUTHS); 1556cb8a054bSGlenn Faden if (chkauthattr(authname, user) == 0) { 1557cb8a054bSGlenn Faden return (Z_ERR); 1558cb8a054bSGlenn Faden } else { 1559cb8a054bSGlenn Faden /* 1560cb8a054bSGlenn Faden * Some subcommands, e.g. install, run subcommands, 1561cb8a054bSGlenn Faden * e.g. sysidcfg, that require a real uid of root, 1562cb8a054bSGlenn Faden * so switch to root, here. 1563cb8a054bSGlenn Faden */ 1564cb8a054bSGlenn Faden if (setuid(0) == -1) { 1565cb8a054bSGlenn Faden zperror(gettext("insufficient privilege"), B_TRUE); 1566cb8a054bSGlenn Faden return (Z_ERR); 1567cb8a054bSGlenn Faden } 1568cb8a054bSGlenn Faden return (Z_OK); 1569cb8a054bSGlenn Faden } 1570cb8a054bSGlenn Faden } 1571cb8a054bSGlenn Faden 15727c478bd9Sstevel@tonic-gate /* 15737c478bd9Sstevel@tonic-gate * Various sanity checks; make sure: 15747c478bd9Sstevel@tonic-gate * 1. We're in the global zone. 15757c478bd9Sstevel@tonic-gate * 2. The calling user has sufficient privilege. 15767c478bd9Sstevel@tonic-gate * 3. The target zone is neither the global zone nor anything starting with 15777c478bd9Sstevel@tonic-gate * "SUNW". 15787c478bd9Sstevel@tonic-gate * 4a. If we're looking for a 'not running' (i.e., configured or installed) 15797c478bd9Sstevel@tonic-gate * zone, the name service knows about it. 15807c478bd9Sstevel@tonic-gate * 4b. For some operations which expect a zone not to be running, that it is 15817c478bd9Sstevel@tonic-gate * not already running (or ready). 15827c478bd9Sstevel@tonic-gate */ 15837c478bd9Sstevel@tonic-gate static int 15847c478bd9Sstevel@tonic-gate sanity_check(char *zone, int cmd_num, boolean_t running, 15859acbbeafSnn35248 boolean_t unsafe_when_running, boolean_t force) 15867c478bd9Sstevel@tonic-gate { 15877c478bd9Sstevel@tonic-gate zone_entry_t *zent; 15887c478bd9Sstevel@tonic-gate priv_set_t *privset; 15899acbbeafSnn35248 zone_state_t state, min_state; 1590108322fbScarlsonj char kernzone[ZONENAME_MAX]; 1591108322fbScarlsonj FILE *fp; 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) { 1594ffbafc53Scomay switch (cmd_num) { 1595ffbafc53Scomay case CMD_HALT: 1596ffbafc53Scomay zerror(gettext("use %s to %s this zone."), "halt(1M)", 15977c478bd9Sstevel@tonic-gate cmd_to_str(cmd_num)); 1598ffbafc53Scomay break; 1599ffbafc53Scomay case CMD_REBOOT: 1600ffbafc53Scomay zerror(gettext("use %s to %s this zone."), 1601ffbafc53Scomay "reboot(1M)", cmd_to_str(cmd_num)); 1602ffbafc53Scomay break; 1603ffbafc53Scomay default: 1604ffbafc53Scomay zerror(gettext("must be in the global zone to %s a " 1605ffbafc53Scomay "zone."), cmd_to_str(cmd_num)); 1606ffbafc53Scomay break; 1607ffbafc53Scomay } 16087c478bd9Sstevel@tonic-gate return (Z_ERR); 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate if ((privset = priv_allocset()) == NULL) { 16127c478bd9Sstevel@tonic-gate zerror(gettext("%s failed"), "priv_allocset"); 16137c478bd9Sstevel@tonic-gate return (Z_ERR); 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate if (getppriv(PRIV_EFFECTIVE, privset) != 0) { 16177c478bd9Sstevel@tonic-gate zerror(gettext("%s failed"), "getppriv"); 16187c478bd9Sstevel@tonic-gate priv_freeset(privset); 16197c478bd9Sstevel@tonic-gate return (Z_ERR); 16207c478bd9Sstevel@tonic-gate } 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate if (priv_isfullset(privset) == B_FALSE) { 16237c478bd9Sstevel@tonic-gate zerror(gettext("only a privileged user may %s a zone."), 16247c478bd9Sstevel@tonic-gate cmd_to_str(cmd_num)); 16257c478bd9Sstevel@tonic-gate priv_freeset(privset); 16267c478bd9Sstevel@tonic-gate return (Z_ERR); 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate priv_freeset(privset); 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate if (zone == NULL) { 16317c478bd9Sstevel@tonic-gate zerror(gettext("no zone specified")); 16327c478bd9Sstevel@tonic-gate return (Z_ERR); 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate 1635cb8a054bSGlenn Faden if (auth_check(username, zone, cmd_num) == Z_ERR) { 1636cb8a054bSGlenn Faden zerror(gettext("User %s is not authorized to %s this zone."), 1637cb8a054bSGlenn Faden username, cmd_to_str(cmd_num)); 1638cb8a054bSGlenn Faden return (Z_ERR); 1639cb8a054bSGlenn Faden } 1640cb8a054bSGlenn Faden 16417c478bd9Sstevel@tonic-gate if (strcmp(zone, GLOBAL_ZONENAME) == 0) { 16427c478bd9Sstevel@tonic-gate zerror(gettext("%s operation is invalid for the global zone."), 16437c478bd9Sstevel@tonic-gate cmd_to_str(cmd_num)); 16447c478bd9Sstevel@tonic-gate return (Z_ERR); 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate if (strncmp(zone, "SUNW", 4) == 0) { 16487c478bd9Sstevel@tonic-gate zerror(gettext("%s operation is invalid for zones starting " 16497c478bd9Sstevel@tonic-gate "with SUNW."), cmd_to_str(cmd_num)); 16507c478bd9Sstevel@tonic-gate return (Z_ERR); 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 1653108322fbScarlsonj if (!zonecfg_in_alt_root()) { 1654108322fbScarlsonj zent = lookup_running_zone(zone); 1655108322fbScarlsonj } else if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL) { 1656108322fbScarlsonj zent = NULL; 1657108322fbScarlsonj } else { 1658108322fbScarlsonj if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(), 1659108322fbScarlsonj kernzone, sizeof (kernzone)) == 0) 1660108322fbScarlsonj zent = lookup_running_zone(kernzone); 1661108322fbScarlsonj else 1662108322fbScarlsonj zent = NULL; 1663108322fbScarlsonj zonecfg_close_scratch(fp); 1664108322fbScarlsonj } 1665108322fbScarlsonj 16667c478bd9Sstevel@tonic-gate /* 16677c478bd9Sstevel@tonic-gate * Look up from the kernel for 'running' zones. 16687c478bd9Sstevel@tonic-gate */ 16699acbbeafSnn35248 if (running && !force) { 16707c478bd9Sstevel@tonic-gate if (zent == NULL) { 16717c478bd9Sstevel@tonic-gate zerror(gettext("not running")); 16727c478bd9Sstevel@tonic-gate return (Z_ERR); 16737c478bd9Sstevel@tonic-gate } 16747c478bd9Sstevel@tonic-gate } else { 16757c478bd9Sstevel@tonic-gate int err; 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate if (unsafe_when_running && zent != NULL) { 16787c478bd9Sstevel@tonic-gate /* check whether the zone is ready or running */ 16797c478bd9Sstevel@tonic-gate if ((err = zone_get_state(zent->zname, 16807c478bd9Sstevel@tonic-gate &zent->zstate_num)) != Z_OK) { 16817c478bd9Sstevel@tonic-gate errno = err; 16827c478bd9Sstevel@tonic-gate zperror2(zent->zname, 16837c478bd9Sstevel@tonic-gate gettext("could not get state")); 16847c478bd9Sstevel@tonic-gate /* can't tell, so hedge */ 16857c478bd9Sstevel@tonic-gate zent->zstate_str = "ready/running"; 16867c478bd9Sstevel@tonic-gate } else { 16877c478bd9Sstevel@tonic-gate zent->zstate_str = 16887c478bd9Sstevel@tonic-gate zone_state_str(zent->zstate_num); 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate zerror(gettext("%s operation is invalid for %s zones."), 16917c478bd9Sstevel@tonic-gate cmd_to_str(cmd_num), zent->zstate_str); 16927c478bd9Sstevel@tonic-gate return (Z_ERR); 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate if ((err = zone_get_state(zone, &state)) != Z_OK) { 16957c478bd9Sstevel@tonic-gate errno = err; 16967c478bd9Sstevel@tonic-gate zperror2(zone, gettext("could not get state")); 16977c478bd9Sstevel@tonic-gate return (Z_ERR); 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate switch (cmd_num) { 17007c478bd9Sstevel@tonic-gate case CMD_UNINSTALL: 17017c478bd9Sstevel@tonic-gate if (state == ZONE_STATE_CONFIGURED) { 17027c478bd9Sstevel@tonic-gate zerror(gettext("is already in state '%s'."), 17037c478bd9Sstevel@tonic-gate zone_state_str(ZONE_STATE_CONFIGURED)); 17047c478bd9Sstevel@tonic-gate return (Z_ERR); 17057c478bd9Sstevel@tonic-gate } 17067c478bd9Sstevel@tonic-gate break; 1707ee519a1fSgjelinek case CMD_ATTACH: 1708edfa49ffS if (state == ZONE_STATE_INSTALLED) { 1709edfa49ffS zerror(gettext("is already %s."), 1710edfa49ffS zone_state_str(ZONE_STATE_INSTALLED)); 1711edfa49ffS return (Z_ERR); 1712edfa49ffS } else if (state == ZONE_STATE_INCOMPLETE && !force) { 1713edfa49ffS zerror(gettext("zone is %s; %s required."), 1714edfa49ffS zone_state_str(ZONE_STATE_INCOMPLETE), 1715edfa49ffS cmd_to_str(CMD_UNINSTALL)); 1716edfa49ffS return (Z_ERR); 1717edfa49ffS } 1718edfa49ffS break; 1719865e09a4Sgjelinek case CMD_CLONE: 17207c478bd9Sstevel@tonic-gate case CMD_INSTALL: 17217c478bd9Sstevel@tonic-gate if (state == ZONE_STATE_INSTALLED) { 17227c478bd9Sstevel@tonic-gate zerror(gettext("is already %s."), 17237c478bd9Sstevel@tonic-gate zone_state_str(ZONE_STATE_INSTALLED)); 17247c478bd9Sstevel@tonic-gate return (Z_ERR); 17257c478bd9Sstevel@tonic-gate } else if (state == ZONE_STATE_INCOMPLETE) { 17267c478bd9Sstevel@tonic-gate zerror(gettext("zone is %s; %s required."), 17277c478bd9Sstevel@tonic-gate zone_state_str(ZONE_STATE_INCOMPLETE), 17287c478bd9Sstevel@tonic-gate cmd_to_str(CMD_UNINSTALL)); 17297c478bd9Sstevel@tonic-gate return (Z_ERR); 17307c478bd9Sstevel@tonic-gate } 17317c478bd9Sstevel@tonic-gate break; 1732ee519a1fSgjelinek case CMD_DETACH: 1733865e09a4Sgjelinek case CMD_MOVE: 17347c478bd9Sstevel@tonic-gate case CMD_READY: 17357c478bd9Sstevel@tonic-gate case CMD_BOOT: 1736108322fbScarlsonj case CMD_MOUNT: 1737555afedfScarlsonj case CMD_MARK: 17389acbbeafSnn35248 if ((cmd_num == CMD_BOOT || cmd_num == CMD_MOUNT) && 17399acbbeafSnn35248 force) 17409acbbeafSnn35248 min_state = ZONE_STATE_INCOMPLETE; 1741edfa49ffS else if (cmd_num == CMD_MARK) 1742edfa49ffS min_state = ZONE_STATE_CONFIGURED; 17439acbbeafSnn35248 else 17449acbbeafSnn35248 min_state = ZONE_STATE_INSTALLED; 17459acbbeafSnn35248 17469acbbeafSnn35248 if (state < min_state) { 17477c478bd9Sstevel@tonic-gate zerror(gettext("must be %s before %s."), 17489acbbeafSnn35248 zone_state_str(min_state), 17497c478bd9Sstevel@tonic-gate cmd_to_str(cmd_num)); 17507c478bd9Sstevel@tonic-gate return (Z_ERR); 17517c478bd9Sstevel@tonic-gate } 17527c478bd9Sstevel@tonic-gate break; 17537c478bd9Sstevel@tonic-gate case CMD_VERIFY: 17547c478bd9Sstevel@tonic-gate if (state == ZONE_STATE_INCOMPLETE) { 17557c478bd9Sstevel@tonic-gate zerror(gettext("zone is %s; %s required."), 17567c478bd9Sstevel@tonic-gate zone_state_str(ZONE_STATE_INCOMPLETE), 17577c478bd9Sstevel@tonic-gate cmd_to_str(CMD_UNINSTALL)); 17587c478bd9Sstevel@tonic-gate return (Z_ERR); 17597c478bd9Sstevel@tonic-gate } 17607c478bd9Sstevel@tonic-gate break; 1761108322fbScarlsonj case CMD_UNMOUNT: 1762108322fbScarlsonj if (state != ZONE_STATE_MOUNTED) { 1763108322fbScarlsonj zerror(gettext("must be %s before %s."), 1764108322fbScarlsonj zone_state_str(ZONE_STATE_MOUNTED), 1765108322fbScarlsonj cmd_to_str(cmd_num)); 1766108322fbScarlsonj return (Z_ERR); 1767108322fbScarlsonj } 1768108322fbScarlsonj break; 1769fbbfbc6eSjv227347 case CMD_SYSBOOT: 1770fbbfbc6eSjv227347 if (state != ZONE_STATE_INSTALLED) { 1771fbbfbc6eSjv227347 zerror(gettext("%s operation is invalid for %s " 1772fbbfbc6eSjv227347 "zones."), cmd_to_str(cmd_num), 1773fbbfbc6eSjv227347 zone_state_str(state)); 1774fbbfbc6eSjv227347 return (Z_ERR); 1775fbbfbc6eSjv227347 } 1776fbbfbc6eSjv227347 break; 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate return (Z_OK); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate static int 17837c478bd9Sstevel@tonic-gate halt_func(int argc, char *argv[]) 17847c478bd9Sstevel@tonic-gate { 17857c478bd9Sstevel@tonic-gate zone_cmd_arg_t zarg; 17867c478bd9Sstevel@tonic-gate int arg; 17877c478bd9Sstevel@tonic-gate 1788108322fbScarlsonj if (zonecfg_in_alt_root()) { 1789108322fbScarlsonj zerror(gettext("cannot halt zone in alternate root")); 1790108322fbScarlsonj return (Z_ERR); 1791108322fbScarlsonj } 1792108322fbScarlsonj 17937c478bd9Sstevel@tonic-gate optind = 0; 17947c478bd9Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 17957c478bd9Sstevel@tonic-gate switch (arg) { 17967c478bd9Sstevel@tonic-gate case '?': 17977c478bd9Sstevel@tonic-gate sub_usage(SHELP_HALT, CMD_HALT); 17987c478bd9Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 17997c478bd9Sstevel@tonic-gate default: 18007c478bd9Sstevel@tonic-gate sub_usage(SHELP_HALT, CMD_HALT); 18017c478bd9Sstevel@tonic-gate return (Z_USAGE); 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate } 18047c478bd9Sstevel@tonic-gate if (argc > optind) { 18057c478bd9Sstevel@tonic-gate sub_usage(SHELP_HALT, CMD_HALT); 18067c478bd9Sstevel@tonic-gate return (Z_USAGE); 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate /* 18097c478bd9Sstevel@tonic-gate * zoneadmd should be the one to decide whether or not to proceed, 18107c478bd9Sstevel@tonic-gate * so even though it seems that the fourth parameter below should 18117c478bd9Sstevel@tonic-gate * perhaps be B_TRUE, it really shouldn't be. 18127c478bd9Sstevel@tonic-gate */ 18139acbbeafSnn35248 if (sanity_check(target_zone, CMD_HALT, B_FALSE, B_FALSE, B_FALSE) 18149acbbeafSnn35248 != Z_OK) 18157c478bd9Sstevel@tonic-gate return (Z_ERR); 18167c478bd9Sstevel@tonic-gate 1817ce28b40eSzt129084 /* 1818ce28b40eSzt129084 * Invoke brand-specific handler. 1819ce28b40eSzt129084 */ 1820ce28b40eSzt129084 if (invoke_brand_handler(CMD_HALT, argv) != Z_OK) 1821ce28b40eSzt129084 return (Z_ERR); 1822ce28b40eSzt129084 18237c478bd9Sstevel@tonic-gate zarg.cmd = Z_HALT; 1824ff17c8bfSgjelinek return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale, 1825ff17c8bfSgjelinek B_TRUE) == 0) ? Z_OK : Z_ERR); 18267c478bd9Sstevel@tonic-gate } 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate static int 18297c478bd9Sstevel@tonic-gate reboot_func(int argc, char *argv[]) 18307c478bd9Sstevel@tonic-gate { 18317c478bd9Sstevel@tonic-gate zone_cmd_arg_t zarg; 18327c478bd9Sstevel@tonic-gate int arg; 18337c478bd9Sstevel@tonic-gate 1834108322fbScarlsonj if (zonecfg_in_alt_root()) { 1835108322fbScarlsonj zerror(gettext("cannot reboot zone in alternate root")); 1836108322fbScarlsonj return (Z_ERR); 1837108322fbScarlsonj } 1838108322fbScarlsonj 18397c478bd9Sstevel@tonic-gate optind = 0; 18407c478bd9Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 18417c478bd9Sstevel@tonic-gate switch (arg) { 18427c478bd9Sstevel@tonic-gate case '?': 18437c478bd9Sstevel@tonic-gate sub_usage(SHELP_REBOOT, CMD_REBOOT); 18447c478bd9Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 18457c478bd9Sstevel@tonic-gate default: 18467c478bd9Sstevel@tonic-gate sub_usage(SHELP_REBOOT, CMD_REBOOT); 18477c478bd9Sstevel@tonic-gate return (Z_USAGE); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate } 18503f2f09c1Sdp 18513f2f09c1Sdp zarg.bootbuf[0] = '\0'; 18523f2f09c1Sdp for (; optind < argc; optind++) { 18533f2f09c1Sdp if (strlcat(zarg.bootbuf, argv[optind], 18543f2f09c1Sdp sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) { 18553f2f09c1Sdp zerror(gettext("Boot argument list too long")); 18563f2f09c1Sdp return (Z_ERR); 18577c478bd9Sstevel@tonic-gate } 18583f2f09c1Sdp if (optind < argc - 1) 18593f2f09c1Sdp if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >= 18603f2f09c1Sdp sizeof (zarg.bootbuf)) { 18613f2f09c1Sdp zerror(gettext("Boot argument list too long")); 18623f2f09c1Sdp return (Z_ERR); 18633f2f09c1Sdp } 18643f2f09c1Sdp } 18653f2f09c1Sdp 18663f2f09c1Sdp 18677c478bd9Sstevel@tonic-gate /* 18687c478bd9Sstevel@tonic-gate * zoneadmd should be the one to decide whether or not to proceed, 18697c478bd9Sstevel@tonic-gate * so even though it seems that the fourth parameter below should 18707c478bd9Sstevel@tonic-gate * perhaps be B_TRUE, it really shouldn't be. 18717c478bd9Sstevel@tonic-gate */ 18729acbbeafSnn35248 if (sanity_check(target_zone, CMD_REBOOT, B_TRUE, B_FALSE, B_FALSE) 18739acbbeafSnn35248 != Z_OK) 18747c478bd9Sstevel@tonic-gate return (Z_ERR); 1875ce28b40eSzt129084 if (verify_details(CMD_REBOOT, argv) != Z_OK) 1876b5abaf04Sgjelinek return (Z_ERR); 18777c478bd9Sstevel@tonic-gate 18787c478bd9Sstevel@tonic-gate zarg.cmd = Z_REBOOT; 1879ff17c8bfSgjelinek return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) == 0) 1880ff17c8bfSgjelinek ? Z_OK : Z_ERR); 1881ff17c8bfSgjelinek } 1882ff17c8bfSgjelinek 1883ff17c8bfSgjelinek static int 1884ff17c8bfSgjelinek get_hook(brand_handle_t bh, char *cmd, size_t len, int (*bp)(brand_handle_t, 1885ff17c8bfSgjelinek const char *, const char *, char *, size_t), char *zonename, char *zonepath) 1886ff17c8bfSgjelinek { 1887ff17c8bfSgjelinek if (strlcpy(cmd, EXEC_PREFIX, len) >= len) 1888ff17c8bfSgjelinek return (Z_ERR); 1889ff17c8bfSgjelinek 1890ff17c8bfSgjelinek if (bp(bh, zonename, zonepath, cmd + EXEC_LEN, len - EXEC_LEN) != 0) 1891ff17c8bfSgjelinek return (Z_ERR); 1892ff17c8bfSgjelinek 1893ff17c8bfSgjelinek if (strlen(cmd) <= EXEC_LEN) 1894ff17c8bfSgjelinek cmd[0] = '\0'; 1895ff17c8bfSgjelinek 1896ff17c8bfSgjelinek return (Z_OK); 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate static int 1900ce28b40eSzt129084 verify_brand(zone_dochandle_t handle, int cmd_num, char *argv[]) 19019acbbeafSnn35248 { 19029acbbeafSnn35248 char cmdbuf[MAXPATHLEN]; 19039acbbeafSnn35248 int err; 19049acbbeafSnn35248 char zonepath[MAXPATHLEN]; 1905123807fbSedp brand_handle_t bh = NULL; 1906ce28b40eSzt129084 int status, i; 19079acbbeafSnn35248 19089acbbeafSnn35248 /* 19099acbbeafSnn35248 * Fetch the verify command from the brand configuration. 19109acbbeafSnn35248 * "exec" the command so that the returned status is that of 19119acbbeafSnn35248 * the command and not the shell. 19129acbbeafSnn35248 */ 1913ff17c8bfSgjelinek if (handle == NULL) { 1914ff17c8bfSgjelinek (void) strlcpy(zonepath, "-", sizeof (zonepath)); 1915ff17c8bfSgjelinek } else if ((err = zonecfg_get_zonepath(handle, zonepath, 1916ff17c8bfSgjelinek sizeof (zonepath))) != Z_OK) { 19179acbbeafSnn35248 errno = err; 1918ce28b40eSzt129084 zperror(cmd_to_str(cmd_num), B_TRUE); 19199acbbeafSnn35248 return (Z_ERR); 19209acbbeafSnn35248 } 1921123807fbSedp if ((bh = brand_open(target_brand)) == NULL) { 19229acbbeafSnn35248 zerror(gettext("missing or invalid brand")); 19239acbbeafSnn35248 return (Z_ERR); 19249acbbeafSnn35248 } 19259acbbeafSnn35248 19269acbbeafSnn35248 /* 19279acbbeafSnn35248 * If the brand has its own verification routine, execute it now. 1928ce28b40eSzt129084 * The verification routine validates the intended zoneadm 1929ce28b40eSzt129084 * operation for the specific brand. The zoneadm subcommand and 1930ce28b40eSzt129084 * all its arguments are passed to the routine. 19319acbbeafSnn35248 */ 1932ff17c8bfSgjelinek err = get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_verify_adm, 1933ff17c8bfSgjelinek target_zone, zonepath); 1934123807fbSedp brand_close(bh); 1935ff17c8bfSgjelinek if (err != Z_OK) 1936ce28b40eSzt129084 return (Z_BRAND_ERROR); 1937ff17c8bfSgjelinek if (cmdbuf[0] == '\0') 1938ce28b40eSzt129084 return (Z_OK); 1939ce28b40eSzt129084 1940ce28b40eSzt129084 if (strlcat(cmdbuf, cmd_to_str(cmd_num), 1941ce28b40eSzt129084 sizeof (cmdbuf)) >= sizeof (cmdbuf)) 1942ce28b40eSzt129084 return (Z_ERR); 1943ce28b40eSzt129084 1944ce28b40eSzt129084 /* Build the argv string */ 1945ce28b40eSzt129084 i = 0; 1946ce28b40eSzt129084 while (argv[i] != NULL) { 1947ce28b40eSzt129084 if ((strlcat(cmdbuf, " ", 1948ce28b40eSzt129084 sizeof (cmdbuf)) >= sizeof (cmdbuf)) || 1949ce28b40eSzt129084 (strlcat(cmdbuf, argv[i++], 1950ce28b40eSzt129084 sizeof (cmdbuf)) >= sizeof (cmdbuf))) 1951ce28b40eSzt129084 return (Z_ERR); 1952ce28b40eSzt129084 } 1953ce28b40eSzt129084 1954d9e728a2Sgjelinek status = do_subproc(cmdbuf); 19559acbbeafSnn35248 err = subproc_status(gettext("brand-specific verification"), 19569acbbeafSnn35248 status, B_FALSE); 19579acbbeafSnn35248 1958ce28b40eSzt129084 return ((err == ZONE_SUBPROC_OK) ? Z_OK : Z_BRAND_ERROR); 19599acbbeafSnn35248 } 19609acbbeafSnn35248 19619acbbeafSnn35248 static int 19627c478bd9Sstevel@tonic-gate verify_rctls(zone_dochandle_t handle) 19637c478bd9Sstevel@tonic-gate { 19647c478bd9Sstevel@tonic-gate struct zone_rctltab rctltab; 19657c478bd9Sstevel@tonic-gate size_t rbs = rctlblk_size(); 19667c478bd9Sstevel@tonic-gate rctlblk_t *rctlblk; 19677c478bd9Sstevel@tonic-gate int error = Z_INVAL; 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate if ((rctlblk = malloc(rbs)) == NULL) { 19707c478bd9Sstevel@tonic-gate zerror(gettext("failed to allocate %lu bytes: %s"), rbs, 19717c478bd9Sstevel@tonic-gate strerror(errno)); 19727c478bd9Sstevel@tonic-gate return (Z_NOMEM); 19737c478bd9Sstevel@tonic-gate } 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate if (zonecfg_setrctlent(handle) != Z_OK) { 19767c478bd9Sstevel@tonic-gate zerror(gettext("zonecfg_setrctlent failed")); 19777c478bd9Sstevel@tonic-gate free(rctlblk); 19787c478bd9Sstevel@tonic-gate return (error); 19797c478bd9Sstevel@tonic-gate } 19807c478bd9Sstevel@tonic-gate 19817c478bd9Sstevel@tonic-gate rctltab.zone_rctl_valptr = NULL; 19827c478bd9Sstevel@tonic-gate while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 19837c478bd9Sstevel@tonic-gate struct zone_rctlvaltab *rctlval; 19847c478bd9Sstevel@tonic-gate const char *name = rctltab.zone_rctl_name; 19857c478bd9Sstevel@tonic-gate 19867c478bd9Sstevel@tonic-gate if (!zonecfg_is_rctl(name)) { 19877c478bd9Sstevel@tonic-gate zerror(gettext("WARNING: Ignoring unrecognized rctl " 19887c478bd9Sstevel@tonic-gate "'%s'."), name); 19897c478bd9Sstevel@tonic-gate zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 19907c478bd9Sstevel@tonic-gate rctltab.zone_rctl_valptr = NULL; 19917c478bd9Sstevel@tonic-gate continue; 19927c478bd9Sstevel@tonic-gate } 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate for (rctlval = rctltab.zone_rctl_valptr; rctlval != NULL; 19957c478bd9Sstevel@tonic-gate rctlval = rctlval->zone_rctlval_next) { 19967c478bd9Sstevel@tonic-gate if (zonecfg_construct_rctlblk(rctlval, rctlblk) 19977c478bd9Sstevel@tonic-gate != Z_OK) { 19987c478bd9Sstevel@tonic-gate zerror(gettext("invalid rctl value: " 19997c478bd9Sstevel@tonic-gate "(priv=%s,limit=%s,action%s)"), 20007c478bd9Sstevel@tonic-gate rctlval->zone_rctlval_priv, 20017c478bd9Sstevel@tonic-gate rctlval->zone_rctlval_limit, 20027c478bd9Sstevel@tonic-gate rctlval->zone_rctlval_action); 20037c478bd9Sstevel@tonic-gate goto out; 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate if (!zonecfg_valid_rctl(name, rctlblk)) { 20067c478bd9Sstevel@tonic-gate zerror(gettext("(priv=%s,limit=%s,action=%s) " 20077c478bd9Sstevel@tonic-gate "is not a valid value for rctl '%s'"), 20087c478bd9Sstevel@tonic-gate rctlval->zone_rctlval_priv, 20097c478bd9Sstevel@tonic-gate rctlval->zone_rctlval_limit, 20107c478bd9Sstevel@tonic-gate rctlval->zone_rctlval_action, 20117c478bd9Sstevel@tonic-gate name); 20127c478bd9Sstevel@tonic-gate goto out; 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 20167c478bd9Sstevel@tonic-gate } 20177c478bd9Sstevel@tonic-gate rctltab.zone_rctl_valptr = NULL; 20187c478bd9Sstevel@tonic-gate error = Z_OK; 20197c478bd9Sstevel@tonic-gate out: 20207c478bd9Sstevel@tonic-gate zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 20217c478bd9Sstevel@tonic-gate (void) zonecfg_endrctlent(handle); 20227c478bd9Sstevel@tonic-gate free(rctlblk); 20237c478bd9Sstevel@tonic-gate return (error); 20247c478bd9Sstevel@tonic-gate } 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate static int 20277c478bd9Sstevel@tonic-gate verify_pool(zone_dochandle_t handle) 20287c478bd9Sstevel@tonic-gate { 20297c478bd9Sstevel@tonic-gate char poolname[MAXPATHLEN]; 20307c478bd9Sstevel@tonic-gate pool_conf_t *poolconf; 20317c478bd9Sstevel@tonic-gate pool_t *pool; 20327c478bd9Sstevel@tonic-gate int status; 20337c478bd9Sstevel@tonic-gate int error; 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate /* 20367c478bd9Sstevel@tonic-gate * This ends up being very similar to the check done in zoneadmd. 20377c478bd9Sstevel@tonic-gate */ 20387c478bd9Sstevel@tonic-gate error = zonecfg_get_pool(handle, poolname, sizeof (poolname)); 20397c478bd9Sstevel@tonic-gate if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) { 20407c478bd9Sstevel@tonic-gate /* 20417c478bd9Sstevel@tonic-gate * No pool specified. 20427c478bd9Sstevel@tonic-gate */ 20437c478bd9Sstevel@tonic-gate return (0); 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate if (error != Z_OK) { 20467c478bd9Sstevel@tonic-gate zperror(gettext("Unable to retrieve pool name from " 20477c478bd9Sstevel@tonic-gate "configuration"), B_TRUE); 20487c478bd9Sstevel@tonic-gate return (error); 20497c478bd9Sstevel@tonic-gate } 20507c478bd9Sstevel@tonic-gate /* 20517c478bd9Sstevel@tonic-gate * Don't do anything if pools aren't enabled. 20527c478bd9Sstevel@tonic-gate */ 20537c478bd9Sstevel@tonic-gate if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) { 20547c478bd9Sstevel@tonic-gate zerror(gettext("WARNING: pools facility not active; " 20557c478bd9Sstevel@tonic-gate "zone will not be bound to pool '%s'."), poolname); 20567c478bd9Sstevel@tonic-gate return (Z_OK); 20577c478bd9Sstevel@tonic-gate } 20587c478bd9Sstevel@tonic-gate /* 20597c478bd9Sstevel@tonic-gate * Try to provide a sane error message if the requested pool doesn't 20607c478bd9Sstevel@tonic-gate * exist. It isn't clear that pools-related failures should 20617c478bd9Sstevel@tonic-gate * necessarily translate to a failure to verify the zone configuration, 20627c478bd9Sstevel@tonic-gate * hence they are not considered errors. 20637c478bd9Sstevel@tonic-gate */ 20647c478bd9Sstevel@tonic-gate if ((poolconf = pool_conf_alloc()) == NULL) { 20657c478bd9Sstevel@tonic-gate zerror(gettext("WARNING: pool_conf_alloc failed; " 20667c478bd9Sstevel@tonic-gate "using default pool")); 20677c478bd9Sstevel@tonic-gate return (Z_OK); 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) != 20707c478bd9Sstevel@tonic-gate PO_SUCCESS) { 20717c478bd9Sstevel@tonic-gate zerror(gettext("WARNING: pool_conf_open failed; " 20727c478bd9Sstevel@tonic-gate "using default pool")); 20737c478bd9Sstevel@tonic-gate pool_conf_free(poolconf); 20747c478bd9Sstevel@tonic-gate return (Z_OK); 20757c478bd9Sstevel@tonic-gate } 20767c478bd9Sstevel@tonic-gate pool = pool_get_pool(poolconf, poolname); 20777c478bd9Sstevel@tonic-gate (void) pool_conf_close(poolconf); 20787c478bd9Sstevel@tonic-gate pool_conf_free(poolconf); 20797c478bd9Sstevel@tonic-gate if (pool == NULL) { 20807c478bd9Sstevel@tonic-gate zerror(gettext("WARNING: pool '%s' not found. " 20817c478bd9Sstevel@tonic-gate "using default pool"), poolname); 20827c478bd9Sstevel@tonic-gate } 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate return (Z_OK); 20857c478bd9Sstevel@tonic-gate } 20867c478bd9Sstevel@tonic-gate 208720c8013fSlling /* 208820c8013fSlling * Verify that the special device/file system exists and is valid. 208920c8013fSlling */ 209020c8013fSlling static int 209120c8013fSlling verify_fs_special(struct zone_fstab *fstab) 209220c8013fSlling { 209393239addSjohnlev struct stat64 st; 209420c8013fSlling 20956cc813faSgjelinek /* 20966cc813faSgjelinek * This validation is really intended for standard zone administration. 20976cc813faSgjelinek * If we are in a mini-root or some other upgrade situation where 20986cc813faSgjelinek * we are using the scratch zone, just by-pass this. 20996cc813faSgjelinek */ 21006cc813faSgjelinek if (zonecfg_in_alt_root()) 21016cc813faSgjelinek return (Z_OK); 21026cc813faSgjelinek 210320c8013fSlling if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0) 210420c8013fSlling return (verify_fs_zfs(fstab)); 210520c8013fSlling 210693239addSjohnlev if (stat64(fstab->zone_fs_special, &st) != 0) { 21075c358068Slling (void) fprintf(stderr, gettext("could not verify fs " 210820c8013fSlling "%s: could not access %s: %s\n"), fstab->zone_fs_dir, 210920c8013fSlling fstab->zone_fs_special, strerror(errno)); 211020c8013fSlling return (Z_ERR); 211120c8013fSlling } 211220c8013fSlling 211320c8013fSlling if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) { 211420c8013fSlling /* 211520c8013fSlling * TRANSLATION_NOTE 211620c8013fSlling * fs and NFS are literals that should 211720c8013fSlling * not be translated. 211820c8013fSlling */ 211920c8013fSlling (void) fprintf(stderr, gettext("cannot verify " 21200b5de56dSgjelinek "fs %s: NFS mounted file system.\n" 21210b5de56dSgjelinek "\tA local file system must be used.\n"), 212220c8013fSlling fstab->zone_fs_special); 212320c8013fSlling return (Z_ERR); 212420c8013fSlling } 212520c8013fSlling 212620c8013fSlling return (Z_OK); 212720c8013fSlling } 212820c8013fSlling 2129b5abaf04Sgjelinek static int 213093239addSjohnlev isregfile(const char *path) 213193239addSjohnlev { 213293239addSjohnlev struct stat64 st; 213393239addSjohnlev 213493239addSjohnlev if (stat64(path, &st) == -1) 213593239addSjohnlev return (-1); 213693239addSjohnlev 213793239addSjohnlev return (S_ISREG(st.st_mode)); 213893239addSjohnlev } 213993239addSjohnlev 214093239addSjohnlev static int 21417c478bd9Sstevel@tonic-gate verify_filesystems(zone_dochandle_t handle) 21427c478bd9Sstevel@tonic-gate { 21437c478bd9Sstevel@tonic-gate int return_code = Z_OK; 21447c478bd9Sstevel@tonic-gate struct zone_fstab fstab; 21457c478bd9Sstevel@tonic-gate char cmdbuf[MAXPATHLEN]; 21467c478bd9Sstevel@tonic-gate struct stat st; 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate /* 21497c478bd9Sstevel@tonic-gate * Since the actual mount point is not known until the dependent mounts 21507c478bd9Sstevel@tonic-gate * are performed, we don't attempt any path validation here: that will 21517c478bd9Sstevel@tonic-gate * happen later when zoneadmd actually does the mounts. 21527c478bd9Sstevel@tonic-gate */ 21537c478bd9Sstevel@tonic-gate if (zonecfg_setfsent(handle) != Z_OK) { 21540b5de56dSgjelinek (void) fprintf(stderr, gettext("could not verify file systems: " 21557c478bd9Sstevel@tonic-gate "unable to enumerate mounts\n")); 21567c478bd9Sstevel@tonic-gate return (Z_ERR); 21577c478bd9Sstevel@tonic-gate } 21587c478bd9Sstevel@tonic-gate while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 21597c478bd9Sstevel@tonic-gate if (!zonecfg_valid_fs_type(fstab.zone_fs_type)) { 21607c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot verify fs %s: " 21617c478bd9Sstevel@tonic-gate "type %s is not allowed.\n"), fstab.zone_fs_dir, 21627c478bd9Sstevel@tonic-gate fstab.zone_fs_type); 21637c478bd9Sstevel@tonic-gate return_code = Z_ERR; 21647c478bd9Sstevel@tonic-gate goto next_fs; 21657c478bd9Sstevel@tonic-gate } 21667c478bd9Sstevel@tonic-gate /* 21677c478bd9Sstevel@tonic-gate * Verify /usr/lib/fs/<fstype>/mount exists. 21687c478bd9Sstevel@tonic-gate */ 21697c478bd9Sstevel@tonic-gate if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/mount", 21707c478bd9Sstevel@tonic-gate fstab.zone_fs_type) > sizeof (cmdbuf)) { 21717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot verify fs %s: " 21727c478bd9Sstevel@tonic-gate "type %s is too long.\n"), fstab.zone_fs_dir, 21737c478bd9Sstevel@tonic-gate fstab.zone_fs_type); 21747c478bd9Sstevel@tonic-gate return_code = Z_ERR; 21757c478bd9Sstevel@tonic-gate goto next_fs; 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate if (stat(cmdbuf, &st) != 0) { 21785ee84fbdSgjelinek (void) fprintf(stderr, gettext("could not verify fs " 21795ee84fbdSgjelinek "%s: could not access %s: %s\n"), fstab.zone_fs_dir, 21807c478bd9Sstevel@tonic-gate cmdbuf, strerror(errno)); 21817c478bd9Sstevel@tonic-gate return_code = Z_ERR; 21827c478bd9Sstevel@tonic-gate goto next_fs; 21837c478bd9Sstevel@tonic-gate } 21847c478bd9Sstevel@tonic-gate if (!S_ISREG(st.st_mode)) { 21855ee84fbdSgjelinek (void) fprintf(stderr, gettext("could not verify fs " 21865ee84fbdSgjelinek "%s: %s is not a regular file\n"), 21875ee84fbdSgjelinek fstab.zone_fs_dir, cmdbuf); 21887c478bd9Sstevel@tonic-gate return_code = Z_ERR; 21897c478bd9Sstevel@tonic-gate goto next_fs; 21907c478bd9Sstevel@tonic-gate } 21917c478bd9Sstevel@tonic-gate /* 219293239addSjohnlev * If zone_fs_raw is set, verify that there's an fsck 219393239addSjohnlev * binary for it. If zone_fs_raw is not set, and it's 219493239addSjohnlev * not a regular file (lofi mount), and there's an fsck 219593239addSjohnlev * binary for it, complain. 21967c478bd9Sstevel@tonic-gate */ 21977c478bd9Sstevel@tonic-gate if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/fsck", 21987c478bd9Sstevel@tonic-gate fstab.zone_fs_type) > sizeof (cmdbuf)) { 21997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot verify fs %s: " 22007c478bd9Sstevel@tonic-gate "type %s is too long.\n"), fstab.zone_fs_dir, 22017c478bd9Sstevel@tonic-gate fstab.zone_fs_type); 22027c478bd9Sstevel@tonic-gate return_code = Z_ERR; 22037c478bd9Sstevel@tonic-gate goto next_fs; 22047c478bd9Sstevel@tonic-gate } 22057c478bd9Sstevel@tonic-gate if (fstab.zone_fs_raw[0] != '\0' && 22067c478bd9Sstevel@tonic-gate (stat(cmdbuf, &st) != 0 || !S_ISREG(st.st_mode))) { 22077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot verify fs %s: " 22087c478bd9Sstevel@tonic-gate "'raw' device specified but " 22097c478bd9Sstevel@tonic-gate "no fsck executable exists for %s\n"), 22107c478bd9Sstevel@tonic-gate fstab.zone_fs_dir, fstab.zone_fs_type); 22117c478bd9Sstevel@tonic-gate return_code = Z_ERR; 22127c478bd9Sstevel@tonic-gate goto next_fs; 221393239addSjohnlev } else if (fstab.zone_fs_raw[0] == '\0' && 221493239addSjohnlev stat(cmdbuf, &st) == 0 && 221593239addSjohnlev isregfile(fstab.zone_fs_special) != 1) { 221693239addSjohnlev (void) fprintf(stderr, gettext("could not verify fs " 221793239addSjohnlev "%s: must specify 'raw' device for %s " 221893239addSjohnlev "file systems\n"), 221993239addSjohnlev fstab.zone_fs_dir, fstab.zone_fs_type); 222093239addSjohnlev return_code = Z_ERR; 222193239addSjohnlev goto next_fs; 22227c478bd9Sstevel@tonic-gate } 222320c8013fSlling 222420c8013fSlling /* Verify fs_special. */ 222520c8013fSlling if ((return_code = verify_fs_special(&fstab)) != Z_OK) 2226b5abaf04Sgjelinek goto next_fs; 222720c8013fSlling 222820c8013fSlling /* Verify fs_raw. */ 2229b5abaf04Sgjelinek if (fstab.zone_fs_raw[0] != '\0' && 2230b5abaf04Sgjelinek stat(fstab.zone_fs_raw, &st) != 0) { 22315ee84fbdSgjelinek /* 22325ee84fbdSgjelinek * TRANSLATION_NOTE 22335ee84fbdSgjelinek * fs is a literal that should not be translated. 22345ee84fbdSgjelinek */ 22355ee84fbdSgjelinek (void) fprintf(stderr, gettext("could not verify fs " 22365ee84fbdSgjelinek "%s: could not access %s: %s\n"), fstab.zone_fs_dir, 2237b5abaf04Sgjelinek fstab.zone_fs_raw, strerror(errno)); 2238b5abaf04Sgjelinek return_code = Z_ERR; 2239b5abaf04Sgjelinek goto next_fs; 2240b5abaf04Sgjelinek } 22417c478bd9Sstevel@tonic-gate next_fs: 22427c478bd9Sstevel@tonic-gate zonecfg_free_fs_option_list(fstab.zone_fs_options); 22437c478bd9Sstevel@tonic-gate } 22447c478bd9Sstevel@tonic-gate (void) zonecfg_endfsent(handle); 22457c478bd9Sstevel@tonic-gate 22467c478bd9Sstevel@tonic-gate return (return_code); 22477c478bd9Sstevel@tonic-gate } 22487c478bd9Sstevel@tonic-gate 22497c478bd9Sstevel@tonic-gate static int 2250ffbafc53Scomay verify_limitpriv(zone_dochandle_t handle) 2251ffbafc53Scomay { 2252ffbafc53Scomay char *privname = NULL; 2253ffbafc53Scomay int err; 2254ffbafc53Scomay priv_set_t *privs; 2255ffbafc53Scomay 2256ffbafc53Scomay if ((privs = priv_allocset()) == NULL) { 2257ffbafc53Scomay zperror(gettext("failed to allocate privilege set"), B_FALSE); 2258ffbafc53Scomay return (Z_NOMEM); 2259ffbafc53Scomay } 2260ffbafc53Scomay err = zonecfg_get_privset(handle, privs, &privname); 2261ffbafc53Scomay switch (err) { 2262ffbafc53Scomay case Z_OK: 2263ffbafc53Scomay break; 2264ffbafc53Scomay case Z_PRIV_PROHIBITED: 2265ffbafc53Scomay (void) fprintf(stderr, gettext("privilege \"%s\" is not " 2266ffbafc53Scomay "permitted within the zone's privilege set\n"), privname); 2267ffbafc53Scomay break; 2268ffbafc53Scomay case Z_PRIV_REQUIRED: 2269ffbafc53Scomay (void) fprintf(stderr, gettext("required privilege \"%s\" is " 2270ffbafc53Scomay "missing from the zone's privilege set\n"), privname); 2271ffbafc53Scomay break; 2272ffbafc53Scomay case Z_PRIV_UNKNOWN: 2273ffbafc53Scomay (void) fprintf(stderr, gettext("unknown privilege \"%s\" " 2274ffbafc53Scomay "specified in the zone's privilege set\n"), privname); 2275ffbafc53Scomay break; 2276ffbafc53Scomay default: 2277ffbafc53Scomay zperror( 2278ffbafc53Scomay gettext("failed to determine the zone's privilege set"), 2279ffbafc53Scomay B_TRUE); 2280ffbafc53Scomay break; 2281ffbafc53Scomay } 2282ffbafc53Scomay free(privname); 2283ffbafc53Scomay priv_freeset(privs); 2284ffbafc53Scomay return (err); 2285ffbafc53Scomay } 2286ffbafc53Scomay 22871390a385Sgjelinek static void 22881390a385Sgjelinek free_local_netifs(int if_cnt, struct net_if **if_list) 22891390a385Sgjelinek { 22901390a385Sgjelinek int i; 22911390a385Sgjelinek 22921390a385Sgjelinek for (i = 0; i < if_cnt; i++) { 22931390a385Sgjelinek free(if_list[i]->name); 22941390a385Sgjelinek free(if_list[i]); 22951390a385Sgjelinek } 22961390a385Sgjelinek free(if_list); 22971390a385Sgjelinek } 22981390a385Sgjelinek 22991390a385Sgjelinek /* 23001390a385Sgjelinek * Get a list of the network interfaces, along with their address families, 23011390a385Sgjelinek * that are plumbed in the global zone. See if_tcp(7p) for a description 23021390a385Sgjelinek * of the ioctls used here. 23031390a385Sgjelinek */ 23041390a385Sgjelinek static int 23051390a385Sgjelinek get_local_netifs(int *if_cnt, struct net_if ***if_list) 23061390a385Sgjelinek { 23071390a385Sgjelinek int s; 23081390a385Sgjelinek int i; 23091390a385Sgjelinek int res = Z_OK; 23101390a385Sgjelinek int space_needed; 23111390a385Sgjelinek int cnt = 0; 23121390a385Sgjelinek struct lifnum if_num; 23131390a385Sgjelinek struct lifconf if_conf; 23141390a385Sgjelinek struct lifreq *if_reqp; 23151390a385Sgjelinek char *if_buf; 23161390a385Sgjelinek struct net_if **local_ifs = NULL; 23171390a385Sgjelinek 23181390a385Sgjelinek *if_cnt = 0; 23191390a385Sgjelinek *if_list = NULL; 23201390a385Sgjelinek 23211390a385Sgjelinek if ((s = socket(SOCKET_AF(AF_INET), SOCK_DGRAM, 0)) < 0) 23221390a385Sgjelinek return (Z_ERR); 23231390a385Sgjelinek 23241390a385Sgjelinek /* 23251390a385Sgjelinek * Come back here in the unlikely event that the number of interfaces 23261390a385Sgjelinek * increases between the time we get the count and the time we do the 23271390a385Sgjelinek * SIOCGLIFCONF ioctl. 23281390a385Sgjelinek */ 23291390a385Sgjelinek retry: 23301390a385Sgjelinek /* Get the number of interfaces. */ 23311390a385Sgjelinek if_num.lifn_family = AF_UNSPEC; 23321390a385Sgjelinek if_num.lifn_flags = LIFC_NOXMIT; 23331390a385Sgjelinek if (ioctl(s, SIOCGLIFNUM, &if_num) < 0) { 23341390a385Sgjelinek (void) close(s); 23351390a385Sgjelinek return (Z_ERR); 23361390a385Sgjelinek } 23371390a385Sgjelinek 23381390a385Sgjelinek /* Get the interface configuration list. */ 23391390a385Sgjelinek space_needed = if_num.lifn_count * sizeof (struct lifreq); 23401390a385Sgjelinek if ((if_buf = malloc(space_needed)) == NULL) { 23411390a385Sgjelinek (void) close(s); 23421390a385Sgjelinek return (Z_ERR); 23431390a385Sgjelinek } 23441390a385Sgjelinek if_conf.lifc_family = AF_UNSPEC; 23451390a385Sgjelinek if_conf.lifc_flags = LIFC_NOXMIT; 23461390a385Sgjelinek if_conf.lifc_len = space_needed; 23471390a385Sgjelinek if_conf.lifc_buf = if_buf; 23481390a385Sgjelinek if (ioctl(s, SIOCGLIFCONF, &if_conf) < 0) { 23491390a385Sgjelinek free(if_buf); 23501390a385Sgjelinek /* 23511390a385Sgjelinek * SIOCGLIFCONF returns EINVAL if the buffer we passed in is 23521390a385Sgjelinek * too small. In this case go back and get the new if cnt. 23531390a385Sgjelinek */ 23541390a385Sgjelinek if (errno == EINVAL) 23551390a385Sgjelinek goto retry; 23561390a385Sgjelinek 23571390a385Sgjelinek (void) close(s); 23581390a385Sgjelinek return (Z_ERR); 23591390a385Sgjelinek } 23601390a385Sgjelinek (void) close(s); 23611390a385Sgjelinek 23621390a385Sgjelinek /* Get the name and address family for each interface. */ 23631390a385Sgjelinek if_reqp = if_conf.lifc_req; 23641390a385Sgjelinek for (i = 0; i < (if_conf.lifc_len / sizeof (struct lifreq)); i++) { 23651390a385Sgjelinek struct net_if **p; 23661390a385Sgjelinek struct lifreq req; 23671390a385Sgjelinek 23681390a385Sgjelinek if (strcmp(LOOPBACK_IF, if_reqp->lifr_name) == 0) { 23691390a385Sgjelinek if_reqp++; 23701390a385Sgjelinek continue; 23711390a385Sgjelinek } 23721390a385Sgjelinek 23731390a385Sgjelinek if ((s = socket(SOCKET_AF(if_reqp->lifr_addr.ss_family), 23741390a385Sgjelinek SOCK_DGRAM, 0)) == -1) { 23751390a385Sgjelinek res = Z_ERR; 23761390a385Sgjelinek break; 23771390a385Sgjelinek } 23781390a385Sgjelinek 23791390a385Sgjelinek (void) strncpy(req.lifr_name, if_reqp->lifr_name, 23801390a385Sgjelinek sizeof (req.lifr_name)); 23811390a385Sgjelinek if (ioctl(s, SIOCGLIFADDR, &req) < 0) { 23821390a385Sgjelinek (void) close(s); 23831390a385Sgjelinek if_reqp++; 23841390a385Sgjelinek continue; 23851390a385Sgjelinek } 23861390a385Sgjelinek 23871390a385Sgjelinek if ((p = (struct net_if **)realloc(local_ifs, 23881390a385Sgjelinek sizeof (struct net_if *) * (cnt + 1))) == NULL) { 23891390a385Sgjelinek res = Z_ERR; 23901390a385Sgjelinek break; 23911390a385Sgjelinek } 23921390a385Sgjelinek local_ifs = p; 23931390a385Sgjelinek 23941390a385Sgjelinek if ((local_ifs[cnt] = malloc(sizeof (struct net_if))) == NULL) { 23951390a385Sgjelinek res = Z_ERR; 23961390a385Sgjelinek break; 23971390a385Sgjelinek } 23981390a385Sgjelinek 23991390a385Sgjelinek if ((local_ifs[cnt]->name = strdup(if_reqp->lifr_name)) 24001390a385Sgjelinek == NULL) { 24011390a385Sgjelinek free(local_ifs[cnt]); 24021390a385Sgjelinek res = Z_ERR; 24031390a385Sgjelinek break; 24041390a385Sgjelinek } 24051390a385Sgjelinek local_ifs[cnt]->af = req.lifr_addr.ss_family; 24061390a385Sgjelinek cnt++; 24071390a385Sgjelinek 24081390a385Sgjelinek (void) close(s); 24091390a385Sgjelinek if_reqp++; 24101390a385Sgjelinek } 24111390a385Sgjelinek 24121390a385Sgjelinek free(if_buf); 24131390a385Sgjelinek 24141390a385Sgjelinek if (res != Z_OK) { 24151390a385Sgjelinek free_local_netifs(cnt, local_ifs); 24161390a385Sgjelinek } else { 24171390a385Sgjelinek *if_cnt = cnt; 24181390a385Sgjelinek *if_list = local_ifs; 24191390a385Sgjelinek } 24201390a385Sgjelinek 24211390a385Sgjelinek return (res); 24221390a385Sgjelinek } 24231390a385Sgjelinek 24241390a385Sgjelinek static char * 24251390a385Sgjelinek af2str(int af) 24261390a385Sgjelinek { 24271390a385Sgjelinek switch (af) { 24281390a385Sgjelinek case AF_INET: 24291390a385Sgjelinek return ("IPv4"); 24301390a385Sgjelinek case AF_INET6: 24311390a385Sgjelinek return ("IPv6"); 24321390a385Sgjelinek default: 24331390a385Sgjelinek return ("Unknown"); 24341390a385Sgjelinek } 24351390a385Sgjelinek } 24361390a385Sgjelinek 24371390a385Sgjelinek /* 24381390a385Sgjelinek * Cross check the network interface name and address family with the 24391390a385Sgjelinek * interfaces that are set up in the global zone so that we can print the 24401390a385Sgjelinek * appropriate error message. 24411390a385Sgjelinek */ 24421390a385Sgjelinek static void 24431390a385Sgjelinek print_net_err(char *phys, char *addr, int af, char *msg) 24441390a385Sgjelinek { 24451390a385Sgjelinek int i; 24461390a385Sgjelinek int local_if_cnt = 0; 24471390a385Sgjelinek struct net_if **local_ifs = NULL; 24481390a385Sgjelinek boolean_t found_if = B_FALSE; 24491390a385Sgjelinek boolean_t found_af = B_FALSE; 24501390a385Sgjelinek 24511390a385Sgjelinek if (get_local_netifs(&local_if_cnt, &local_ifs) != Z_OK) { 24521390a385Sgjelinek (void) fprintf(stderr, 24531390a385Sgjelinek gettext("could not verify %s %s=%s %s=%s\n\t%s\n"), 24541390a385Sgjelinek "net", "address", addr, "physical", phys, msg); 24551390a385Sgjelinek return; 24561390a385Sgjelinek } 24571390a385Sgjelinek 24581390a385Sgjelinek for (i = 0; i < local_if_cnt; i++) { 24591390a385Sgjelinek if (strcmp(phys, local_ifs[i]->name) == 0) { 24601390a385Sgjelinek found_if = B_TRUE; 24611390a385Sgjelinek if (af == local_ifs[i]->af) { 24621390a385Sgjelinek found_af = B_TRUE; 24631390a385Sgjelinek break; 24641390a385Sgjelinek } 24651390a385Sgjelinek } 24661390a385Sgjelinek } 24671390a385Sgjelinek 24681390a385Sgjelinek free_local_netifs(local_if_cnt, local_ifs); 24691390a385Sgjelinek 24701390a385Sgjelinek if (!found_if) { 24711390a385Sgjelinek (void) fprintf(stderr, 24721390a385Sgjelinek gettext("could not verify %s %s=%s\n\t" 24731390a385Sgjelinek "network interface %s is not plumbed in the global zone\n"), 24741390a385Sgjelinek "net", "physical", phys, phys); 24751390a385Sgjelinek return; 24761390a385Sgjelinek } 24771390a385Sgjelinek 24781390a385Sgjelinek /* 24791390a385Sgjelinek * Print this error if we were unable to find the address family 24801390a385Sgjelinek * for this interface. If the af variable is not initialized to 24811390a385Sgjelinek * to something meaningful by the caller (not AF_UNSPEC) then we 24821390a385Sgjelinek * also skip this message since it wouldn't be informative. 24831390a385Sgjelinek */ 24841390a385Sgjelinek if (!found_af && af != AF_UNSPEC) { 24851390a385Sgjelinek (void) fprintf(stderr, 24861390a385Sgjelinek gettext("could not verify %s %s=%s %s=%s\n\tthe %s address " 2487f4b3ec61Sdh155122 "family is not configured on this network interface in " 2488f4b3ec61Sdh155122 "the\n\tglobal zone\n"), 24891390a385Sgjelinek "net", "address", addr, "physical", phys, af2str(af)); 24901390a385Sgjelinek return; 24911390a385Sgjelinek } 24921390a385Sgjelinek 24931390a385Sgjelinek (void) fprintf(stderr, 24941390a385Sgjelinek gettext("could not verify %s %s=%s %s=%s\n\t%s\n"), 24951390a385Sgjelinek "net", "address", addr, "physical", phys, msg); 24961390a385Sgjelinek } 24971390a385Sgjelinek 2498ffbafc53Scomay static int 2499ce28b40eSzt129084 verify_handle(int cmd_num, zone_dochandle_t handle, char *argv[]) 25007c478bd9Sstevel@tonic-gate { 25017c478bd9Sstevel@tonic-gate struct zone_nwiftab nwiftab; 25027c478bd9Sstevel@tonic-gate int return_code = Z_OK; 25037c478bd9Sstevel@tonic-gate int err; 2504108322fbScarlsonj boolean_t in_alt_root; 2505f4b3ec61Sdh155122 zone_iptype_t iptype; 25062b24ab6bSSebastien Roy dladm_handle_t dh; 25072b24ab6bSSebastien Roy dladm_status_t status; 25082b24ab6bSSebastien Roy datalink_id_t linkid; 25092b24ab6bSSebastien Roy char errmsg[DLADM_STRSIZE]; 25107c478bd9Sstevel@tonic-gate 2511108322fbScarlsonj in_alt_root = zonecfg_in_alt_root(); 2512108322fbScarlsonj if (in_alt_root) 2513108322fbScarlsonj goto no_net; 2514108322fbScarlsonj 2515f4b3ec61Sdh155122 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK) { 2516f4b3ec61Sdh155122 errno = err; 2517f4b3ec61Sdh155122 zperror(cmd_to_str(cmd_num), B_TRUE); 2518f4b3ec61Sdh155122 zonecfg_fini_handle(handle); 2519f4b3ec61Sdh155122 return (Z_ERR); 2520f4b3ec61Sdh155122 } 25217c478bd9Sstevel@tonic-gate if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 25227c478bd9Sstevel@tonic-gate errno = err; 25237c478bd9Sstevel@tonic-gate zperror(cmd_to_str(cmd_num), B_TRUE); 25247c478bd9Sstevel@tonic-gate zonecfg_fini_handle(handle); 25257c478bd9Sstevel@tonic-gate return (Z_ERR); 25267c478bd9Sstevel@tonic-gate } 25277c478bd9Sstevel@tonic-gate while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 25287c478bd9Sstevel@tonic-gate struct lifreq lifr; 25291390a385Sgjelinek sa_family_t af = AF_UNSPEC; 2530f4b3ec61Sdh155122 char dl_owner_zname[ZONENAME_MAX]; 2531f4b3ec61Sdh155122 zoneid_t dl_owner_zid; 2532f4b3ec61Sdh155122 zoneid_t target_zid; 2533f4b3ec61Sdh155122 int res; 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate /* skip any loopback interfaces */ 25367c478bd9Sstevel@tonic-gate if (strcmp(nwiftab.zone_nwif_physical, "lo0") == 0) 25377c478bd9Sstevel@tonic-gate continue; 2538f4b3ec61Sdh155122 switch (iptype) { 2539f4b3ec61Sdh155122 case ZS_SHARED: 2540f4b3ec61Sdh155122 if ((res = zonecfg_valid_net_address( 2541f4b3ec61Sdh155122 nwiftab.zone_nwif_address, &lifr)) != Z_OK) { 25421390a385Sgjelinek print_net_err(nwiftab.zone_nwif_physical, 25431390a385Sgjelinek nwiftab.zone_nwif_address, af, 25441390a385Sgjelinek zonecfg_strerror(res)); 25457c478bd9Sstevel@tonic-gate return_code = Z_ERR; 25467c478bd9Sstevel@tonic-gate continue; 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate af = lifr.lifr_addr.ss_family; 2549f4b3ec61Sdh155122 if (!zonecfg_ifname_exists(af, 2550f4b3ec61Sdh155122 nwiftab.zone_nwif_physical)) { 255122321485Svp157776 /* 2552f4b3ec61Sdh155122 * The interface failed to come up. We continue 2553f4b3ec61Sdh155122 * on anyway for the sake of consistency: a 2554f4b3ec61Sdh155122 * zone is not shut down if the interface fails 2555f4b3ec61Sdh155122 * any time after boot, nor does the global zone 2556f4b3ec61Sdh155122 * fail to boot if an interface fails. 255722321485Svp157776 */ 255822321485Svp157776 (void) fprintf(stderr, 2559f4b3ec61Sdh155122 gettext("WARNING: skipping network " 2560f4b3ec61Sdh155122 "interface '%s' which may not be " 2561f4b3ec61Sdh155122 "present/plumbed in the global " 2562f4b3ec61Sdh155122 "zone.\n"), 256322321485Svp157776 nwiftab.zone_nwif_physical); 25647c478bd9Sstevel@tonic-gate } 2565f4b3ec61Sdh155122 break; 2566f4b3ec61Sdh155122 case ZS_EXCLUSIVE: 2567f4b3ec61Sdh155122 /* Warning if it exists for either IPv4 or IPv6 */ 2568f4b3ec61Sdh155122 2569f4b3ec61Sdh155122 if (zonecfg_ifname_exists(AF_INET, 2570f4b3ec61Sdh155122 nwiftab.zone_nwif_physical) || 2571f4b3ec61Sdh155122 zonecfg_ifname_exists(AF_INET6, 2572f4b3ec61Sdh155122 nwiftab.zone_nwif_physical)) { 2573f4b3ec61Sdh155122 (void) fprintf(stderr, 2574f4b3ec61Sdh155122 gettext("WARNING: skipping network " 2575f4b3ec61Sdh155122 "interface '%s' which is used in the " 2576f4b3ec61Sdh155122 "global zone.\n"), 2577f4b3ec61Sdh155122 nwiftab.zone_nwif_physical); 2578f4b3ec61Sdh155122 break; 2579f4b3ec61Sdh155122 } 2580948f2876Sss150715 2581f4b3ec61Sdh155122 /* 25822b24ab6bSSebastien Roy * Verify that the datalink exists and that it isn't 25832b24ab6bSSebastien Roy * already assigned to a zone. 2584f4b3ec61Sdh155122 */ 25852b24ab6bSSebastien Roy if ((status = dladm_open(&dh)) == DLADM_STATUS_OK) { 25862b24ab6bSSebastien Roy status = dladm_name2info(dh, 25872b24ab6bSSebastien Roy nwiftab.zone_nwif_physical, &linkid, NULL, 25882b24ab6bSSebastien Roy NULL, NULL); 25892b24ab6bSSebastien Roy dladm_close(dh); 25902b24ab6bSSebastien Roy } 25912b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) { 2592f4b3ec61Sdh155122 (void) fprintf(stderr, 2593f4b3ec61Sdh155122 gettext("WARNING: skipping network " 25942b24ab6bSSebastien Roy "interface '%s': %s\n"), 2595948f2876Sss150715 nwiftab.zone_nwif_physical, 25962b24ab6bSSebastien Roy dladm_status2str(status, errmsg)); 2597f4b3ec61Sdh155122 break; 2598f4b3ec61Sdh155122 } 2599f4b3ec61Sdh155122 dl_owner_zid = ALL_ZONES; 26002b24ab6bSSebastien Roy if (zone_check_datalink(&dl_owner_zid, linkid) != 0) 2601f4b3ec61Sdh155122 break; 2602f4b3ec61Sdh155122 2603f4b3ec61Sdh155122 /* 2604f4b3ec61Sdh155122 * If the zone being verified is 2605f4b3ec61Sdh155122 * running and owns the interface 2606f4b3ec61Sdh155122 */ 2607f4b3ec61Sdh155122 target_zid = getzoneidbyname(target_zone); 2608f4b3ec61Sdh155122 if (target_zid == dl_owner_zid) 2609f4b3ec61Sdh155122 break; 2610f4b3ec61Sdh155122 2611f4b3ec61Sdh155122 /* Zone id match failed, use name to check */ 2612f4b3ec61Sdh155122 if (getzonenamebyid(dl_owner_zid, dl_owner_zname, 2613f4b3ec61Sdh155122 ZONENAME_MAX) < 0) { 2614f4b3ec61Sdh155122 /* No name, show ID instead */ 2615f4b3ec61Sdh155122 (void) snprintf(dl_owner_zname, ZONENAME_MAX, 2616f4b3ec61Sdh155122 "<%d>", dl_owner_zid); 2617f4b3ec61Sdh155122 } else if (strcmp(dl_owner_zname, target_zone) == 0) 2618f4b3ec61Sdh155122 break; 2619f4b3ec61Sdh155122 2620f4b3ec61Sdh155122 /* 2621f4b3ec61Sdh155122 * Note here we only report a warning that 2622f4b3ec61Sdh155122 * the interface is already in use by another 2623f4b3ec61Sdh155122 * running zone, and the verify process just 2624f4b3ec61Sdh155122 * goes on, if the interface is still in use 2625f4b3ec61Sdh155122 * when this zone really boots up, zoneadmd 2626f4b3ec61Sdh155122 * will find it. If the name of the zone which 2627f4b3ec61Sdh155122 * owns this interface cannot be determined, 2628f4b3ec61Sdh155122 * then it is not possible to determine if there 2629f4b3ec61Sdh155122 * is a conflict so just report it as a warning. 2630f4b3ec61Sdh155122 */ 2631f4b3ec61Sdh155122 (void) fprintf(stderr, 2632f4b3ec61Sdh155122 gettext("WARNING: skipping network interface " 2633f4b3ec61Sdh155122 "'%s' which is used by the non-global zone " 2634f4b3ec61Sdh155122 "'%s'.\n"), nwiftab.zone_nwif_physical, 2635f4b3ec61Sdh155122 dl_owner_zname); 2636f4b3ec61Sdh155122 break; 2637f4b3ec61Sdh155122 } 26387c478bd9Sstevel@tonic-gate } 26397c478bd9Sstevel@tonic-gate (void) zonecfg_endnwifent(handle); 2640108322fbScarlsonj no_net: 26417c478bd9Sstevel@tonic-gate 2642e7f3c547Sgjelinek /* verify that lofs has not been excluded from the kernel */ 26438cd327d5Sgjelinek if (!(cmd_num == CMD_DETACH || cmd_num == CMD_ATTACH || 26448cd327d5Sgjelinek cmd_num == CMD_MOVE || cmd_num == CMD_CLONE) && 26458cd327d5Sgjelinek modctl(MODLOAD, 1, "fs/lofs", NULL) != 0) { 2646e7f3c547Sgjelinek if (errno == ENXIO) 2647e7f3c547Sgjelinek (void) fprintf(stderr, gettext("could not verify " 2648e7f3c547Sgjelinek "lofs(7FS): possibly excluded in /etc/system\n")); 2649e7f3c547Sgjelinek else 2650e7f3c547Sgjelinek (void) fprintf(stderr, gettext("could not verify " 2651e7f3c547Sgjelinek "lofs(7FS): %s\n"), strerror(errno)); 2652e7f3c547Sgjelinek return_code = Z_ERR; 2653e7f3c547Sgjelinek } 2654e7f3c547Sgjelinek 26557c478bd9Sstevel@tonic-gate if (verify_filesystems(handle) != Z_OK) 26567c478bd9Sstevel@tonic-gate return_code = Z_ERR; 2657108322fbScarlsonj if (!in_alt_root && verify_rctls(handle) != Z_OK) 26587c478bd9Sstevel@tonic-gate return_code = Z_ERR; 2659108322fbScarlsonj if (!in_alt_root && verify_pool(handle) != Z_OK) 26607c478bd9Sstevel@tonic-gate return_code = Z_ERR; 2661ce28b40eSzt129084 if (!in_alt_root && verify_brand(handle, cmd_num, argv) != Z_OK) 26629acbbeafSnn35248 return_code = Z_ERR; 2663fa9e4066Sahrens if (!in_alt_root && verify_datasets(handle) != Z_OK) 2664fa9e4066Sahrens return_code = Z_ERR; 2665ffbafc53Scomay 2666ffbafc53Scomay /* 2667ffbafc53Scomay * As the "mount" command is used for patching/upgrading of zones 2668ffbafc53Scomay * or other maintenance processes, the zone's privilege set is not 2669ffbafc53Scomay * checked in this case. Instead, the default, safe set of 2670ffbafc53Scomay * privileges will be used when this zone is created in the 2671ffbafc53Scomay * kernel. 2672ffbafc53Scomay */ 2673ffbafc53Scomay if (!in_alt_root && cmd_num != CMD_MOUNT && 2674ffbafc53Scomay verify_limitpriv(handle) != Z_OK) 2675ffbafc53Scomay return_code = Z_ERR; 26768cd327d5Sgjelinek 26778cd327d5Sgjelinek return (return_code); 26788cd327d5Sgjelinek } 26798cd327d5Sgjelinek 26808cd327d5Sgjelinek static int 2681ce28b40eSzt129084 verify_details(int cmd_num, char *argv[]) 26828cd327d5Sgjelinek { 26838cd327d5Sgjelinek zone_dochandle_t handle; 26848cd327d5Sgjelinek char zonepath[MAXPATHLEN], checkpath[MAXPATHLEN]; 26858cd327d5Sgjelinek int return_code = Z_OK; 26868cd327d5Sgjelinek int err; 26878cd327d5Sgjelinek 26888cd327d5Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 26898cd327d5Sgjelinek zperror(cmd_to_str(cmd_num), B_TRUE); 26908cd327d5Sgjelinek return (Z_ERR); 26918cd327d5Sgjelinek } 26928cd327d5Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 26938cd327d5Sgjelinek errno = err; 26948cd327d5Sgjelinek zperror(cmd_to_str(cmd_num), B_TRUE); 26958cd327d5Sgjelinek zonecfg_fini_handle(handle); 26968cd327d5Sgjelinek return (Z_ERR); 26978cd327d5Sgjelinek } 26988cd327d5Sgjelinek if ((err = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath))) != 26998cd327d5Sgjelinek Z_OK) { 27008cd327d5Sgjelinek errno = err; 27018cd327d5Sgjelinek zperror(cmd_to_str(cmd_num), B_TRUE); 27028cd327d5Sgjelinek zonecfg_fini_handle(handle); 27038cd327d5Sgjelinek return (Z_ERR); 27048cd327d5Sgjelinek } 27058cd327d5Sgjelinek /* 27068cd327d5Sgjelinek * zonecfg_get_zonepath() gets its data from the XML repository. 27078cd327d5Sgjelinek * Verify this against the index file, which is checked first by 27088cd327d5Sgjelinek * zone_get_zonepath(). If they don't match, bail out. 27098cd327d5Sgjelinek */ 27108cd327d5Sgjelinek if ((err = zone_get_zonepath(target_zone, checkpath, 27118cd327d5Sgjelinek sizeof (checkpath))) != Z_OK) { 27128cd327d5Sgjelinek errno = err; 27138cd327d5Sgjelinek zperror2(target_zone, gettext("could not get zone path")); 2714e767a340Sgjelinek zonecfg_fini_handle(handle); 27158cd327d5Sgjelinek return (Z_ERR); 27168cd327d5Sgjelinek } 27178cd327d5Sgjelinek if (strcmp(zonepath, checkpath) != 0) { 27188cd327d5Sgjelinek /* 27198cd327d5Sgjelinek * TRANSLATION_NOTE 27208cd327d5Sgjelinek * XML and zonepath are literals that should not be translated. 27218cd327d5Sgjelinek */ 27228cd327d5Sgjelinek (void) fprintf(stderr, gettext("The XML repository has " 27238cd327d5Sgjelinek "zonepath '%s',\nbut the index file has zonepath '%s'.\n" 27248cd327d5Sgjelinek "These must match, so fix the incorrect entry.\n"), 27258cd327d5Sgjelinek zonepath, checkpath); 2726e767a340Sgjelinek zonecfg_fini_handle(handle); 27278cd327d5Sgjelinek return (Z_ERR); 27288cd327d5Sgjelinek } 2729ca733e25S if (cmd_num != CMD_ATTACH && 2730ca733e25S validate_zonepath(zonepath, cmd_num) != Z_OK) { 27318cd327d5Sgjelinek (void) fprintf(stderr, gettext("could not verify zonepath %s " 27328cd327d5Sgjelinek "because of the above errors.\n"), zonepath); 27338cd327d5Sgjelinek return_code = Z_ERR; 27348cd327d5Sgjelinek } 27358cd327d5Sgjelinek 2736ce28b40eSzt129084 if (verify_handle(cmd_num, handle, argv) != Z_OK) 27378cd327d5Sgjelinek return_code = Z_ERR; 27388cd327d5Sgjelinek 27397c478bd9Sstevel@tonic-gate zonecfg_fini_handle(handle); 27407c478bd9Sstevel@tonic-gate if (return_code == Z_ERR) 27417c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 27427c478bd9Sstevel@tonic-gate gettext("%s: zone %s failed to verify\n"), 27437c478bd9Sstevel@tonic-gate execname, target_zone); 27447c478bd9Sstevel@tonic-gate return (return_code); 27457c478bd9Sstevel@tonic-gate } 27467c478bd9Sstevel@tonic-gate 27477c478bd9Sstevel@tonic-gate static int 27487c478bd9Sstevel@tonic-gate verify_func(int argc, char *argv[]) 27497c478bd9Sstevel@tonic-gate { 27507c478bd9Sstevel@tonic-gate int arg; 27517c478bd9Sstevel@tonic-gate 27527c478bd9Sstevel@tonic-gate optind = 0; 27537c478bd9Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 27547c478bd9Sstevel@tonic-gate switch (arg) { 27557c478bd9Sstevel@tonic-gate case '?': 27567c478bd9Sstevel@tonic-gate sub_usage(SHELP_VERIFY, CMD_VERIFY); 27577c478bd9Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 27587c478bd9Sstevel@tonic-gate default: 27597c478bd9Sstevel@tonic-gate sub_usage(SHELP_VERIFY, CMD_VERIFY); 27607c478bd9Sstevel@tonic-gate return (Z_USAGE); 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate } 27637c478bd9Sstevel@tonic-gate if (argc > optind) { 27647c478bd9Sstevel@tonic-gate sub_usage(SHELP_VERIFY, CMD_VERIFY); 27657c478bd9Sstevel@tonic-gate return (Z_USAGE); 27667c478bd9Sstevel@tonic-gate } 27679acbbeafSnn35248 if (sanity_check(target_zone, CMD_VERIFY, B_FALSE, B_FALSE, B_FALSE) 27689acbbeafSnn35248 != Z_OK) 27697c478bd9Sstevel@tonic-gate return (Z_ERR); 2770ce28b40eSzt129084 return (verify_details(CMD_VERIFY, argv)); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate 27739acbbeafSnn35248 static int 2774ff17c8bfSgjelinek addoptions(char *buf, char *argv[], size_t len) 2775ff17c8bfSgjelinek { 2776ff17c8bfSgjelinek int i = 0; 2777ff17c8bfSgjelinek 2778ff17c8bfSgjelinek if (buf[0] == '\0') 2779ff17c8bfSgjelinek return (Z_OK); 2780ff17c8bfSgjelinek 2781ff17c8bfSgjelinek while (argv[i] != NULL) { 2782ff17c8bfSgjelinek if (strlcat(buf, " ", len) >= len || 2783ff17c8bfSgjelinek strlcat(buf, argv[i++], len) >= len) { 2784ff17c8bfSgjelinek zerror("Command line too long"); 2785ff17c8bfSgjelinek return (Z_ERR); 2786ff17c8bfSgjelinek } 2787ff17c8bfSgjelinek } 2788ff17c8bfSgjelinek 2789ff17c8bfSgjelinek return (Z_OK); 2790ff17c8bfSgjelinek } 2791ff17c8bfSgjelinek 2792ff17c8bfSgjelinek static int 27939acbbeafSnn35248 addopt(char *buf, int opt, char *optarg, size_t bufsize) 27949acbbeafSnn35248 { 27959acbbeafSnn35248 char optstring[4]; 27969acbbeafSnn35248 27979acbbeafSnn35248 if (opt > 0) 27989acbbeafSnn35248 (void) sprintf(optstring, " -%c", opt); 27999acbbeafSnn35248 else 28009acbbeafSnn35248 (void) strcpy(optstring, " "); 28019acbbeafSnn35248 28029acbbeafSnn35248 if ((strlcat(buf, optstring, bufsize) > bufsize)) 28039acbbeafSnn35248 return (Z_ERR); 2804ff17c8bfSgjelinek 28059acbbeafSnn35248 if ((optarg != NULL) && (strlcat(buf, optarg, bufsize) > bufsize)) 28069acbbeafSnn35248 return (Z_ERR); 2807ff17c8bfSgjelinek 28089acbbeafSnn35248 return (Z_OK); 28099acbbeafSnn35248 } 28107c478bd9Sstevel@tonic-gate 2811ff17c8bfSgjelinek /* ARGSUSED */ 28127c478bd9Sstevel@tonic-gate static int 28137c478bd9Sstevel@tonic-gate install_func(int argc, char *argv[]) 28147c478bd9Sstevel@tonic-gate { 28159acbbeafSnn35248 char cmdbuf[MAXPATHLEN]; 28161100f00dSgjelinek char postcmdbuf[MAXPATHLEN]; 28177c478bd9Sstevel@tonic-gate int lockfd; 28189acbbeafSnn35248 int arg, err, subproc_err; 28197c478bd9Sstevel@tonic-gate char zonepath[MAXPATHLEN]; 2820123807fbSedp brand_handle_t bh = NULL; 28217c478bd9Sstevel@tonic-gate int status; 28221100f00dSgjelinek boolean_t do_postinstall = B_FALSE; 2823ff17c8bfSgjelinek boolean_t brand_help = B_FALSE; 28249acbbeafSnn35248 char opts[128]; 28259acbbeafSnn35248 28269acbbeafSnn35248 if (target_zone == NULL) { 28279acbbeafSnn35248 sub_usage(SHELP_INSTALL, CMD_INSTALL); 28289acbbeafSnn35248 return (Z_USAGE); 28299acbbeafSnn35248 } 28307c478bd9Sstevel@tonic-gate 2831108322fbScarlsonj if (zonecfg_in_alt_root()) { 2832108322fbScarlsonj zerror(gettext("cannot install zone in alternate root")); 2833108322fbScarlsonj return (Z_ERR); 2834108322fbScarlsonj } 2835108322fbScarlsonj 28369acbbeafSnn35248 if ((err = zone_get_zonepath(target_zone, zonepath, 28379acbbeafSnn35248 sizeof (zonepath))) != Z_OK) { 28389acbbeafSnn35248 errno = err; 28399acbbeafSnn35248 zperror2(target_zone, gettext("could not get zone path")); 28409acbbeafSnn35248 return (Z_ERR); 28419acbbeafSnn35248 } 28429acbbeafSnn35248 28439acbbeafSnn35248 /* Fetch the install command from the brand configuration. */ 2844123807fbSedp if ((bh = brand_open(target_brand)) == NULL) { 28459acbbeafSnn35248 zerror(gettext("missing or invalid brand")); 28469acbbeafSnn35248 return (Z_ERR); 28479acbbeafSnn35248 } 28489acbbeafSnn35248 2849ff17c8bfSgjelinek if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_install, 2850ff17c8bfSgjelinek target_zone, zonepath) != Z_OK) { 28519acbbeafSnn35248 zerror("invalid brand configuration: missing install resource"); 2852123807fbSedp brand_close(bh); 28539acbbeafSnn35248 return (Z_ERR); 28549acbbeafSnn35248 } 28559acbbeafSnn35248 2856ff17c8bfSgjelinek if (get_hook(bh, postcmdbuf, sizeof (postcmdbuf), brand_get_postinstall, 2857ff17c8bfSgjelinek target_zone, zonepath) != Z_OK) { 28581100f00dSgjelinek zerror("invalid brand configuration: missing postinstall " 28591100f00dSgjelinek "resource"); 28601100f00dSgjelinek brand_close(bh); 28611100f00dSgjelinek return (Z_ERR); 28621100f00dSgjelinek } 28631100f00dSgjelinek 2864ff17c8bfSgjelinek if (postcmdbuf[0] != '\0') 2865ff17c8bfSgjelinek do_postinstall = B_TRUE; 2866ff17c8bfSgjelinek 28679acbbeafSnn35248 (void) strcpy(opts, "?x:"); 28689acbbeafSnn35248 /* 28699acbbeafSnn35248 * Fetch the list of recognized command-line options from 28709acbbeafSnn35248 * the brand configuration file. 28719acbbeafSnn35248 */ 2872123807fbSedp if (brand_get_installopts(bh, opts + strlen(opts), 28739acbbeafSnn35248 sizeof (opts) - strlen(opts)) != 0) { 28749acbbeafSnn35248 zerror("invalid brand configuration: missing " 28759acbbeafSnn35248 "install options resource"); 2876123807fbSedp brand_close(bh); 28779acbbeafSnn35248 return (Z_ERR); 28789acbbeafSnn35248 } 2879ff17c8bfSgjelinek 2880123807fbSedp brand_close(bh); 28819acbbeafSnn35248 2882ff17c8bfSgjelinek if (cmdbuf[0] == '\0') { 2883ff17c8bfSgjelinek zerror("Missing brand install command"); 2884ff17c8bfSgjelinek return (Z_ERR); 2885ff17c8bfSgjelinek } 2886ff17c8bfSgjelinek 2887ff17c8bfSgjelinek /* Check the argv string for args we handle internally */ 28887c478bd9Sstevel@tonic-gate optind = 0; 2889ff17c8bfSgjelinek opterr = 0; 28909acbbeafSnn35248 while ((arg = getopt(argc, argv, opts)) != EOF) { 28917c478bd9Sstevel@tonic-gate switch (arg) { 28927c478bd9Sstevel@tonic-gate case '?': 2893ff17c8bfSgjelinek if (optopt == '?') { 28947c478bd9Sstevel@tonic-gate sub_usage(SHELP_INSTALL, CMD_INSTALL); 2895ff17c8bfSgjelinek brand_help = B_TRUE; 28960b5de56dSgjelinek } 2897ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 28980b5de56dSgjelinek break; 28997c478bd9Sstevel@tonic-gate default: 2900ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 2901ff17c8bfSgjelinek break; 29027c478bd9Sstevel@tonic-gate } 29039acbbeafSnn35248 29049acbbeafSnn35248 /* 2905ff17c8bfSgjelinek * Append the option to the command line passed to the 2906ff17c8bfSgjelinek * brand-specific install and postinstall routines. 29079acbbeafSnn35248 */ 2908ff17c8bfSgjelinek if (addopt(cmdbuf, optopt, optarg, sizeof (cmdbuf)) != Z_OK) { 29099acbbeafSnn35248 zerror("Install command line too long"); 29109acbbeafSnn35248 return (Z_ERR); 29117c478bd9Sstevel@tonic-gate } 2912ff17c8bfSgjelinek if (addopt(postcmdbuf, optopt, optarg, sizeof (postcmdbuf)) 2913ff17c8bfSgjelinek != Z_OK) { 29141100f00dSgjelinek zerror("Post-Install command line too long"); 29151100f00dSgjelinek return (Z_ERR); 29161100f00dSgjelinek } 29179acbbeafSnn35248 } 29189acbbeafSnn35248 29199acbbeafSnn35248 for (; optind < argc; optind++) { 2920ff17c8bfSgjelinek if (addopt(cmdbuf, 0, argv[optind], sizeof (cmdbuf)) != Z_OK) { 29219acbbeafSnn35248 zerror("Install command line too long"); 29229acbbeafSnn35248 return (Z_ERR); 29239acbbeafSnn35248 } 2924ff17c8bfSgjelinek 2925ff17c8bfSgjelinek if (addopt(postcmdbuf, 0, argv[optind], sizeof (postcmdbuf)) 2926ff17c8bfSgjelinek != Z_OK) { 29271100f00dSgjelinek zerror("Post-Install command line too long"); 29281100f00dSgjelinek return (Z_ERR); 29291100f00dSgjelinek } 29309acbbeafSnn35248 } 29319acbbeafSnn35248 2932ff17c8bfSgjelinek if (!brand_help) { 2933ff17c8bfSgjelinek if (sanity_check(target_zone, CMD_INSTALL, B_FALSE, B_TRUE, 2934ff17c8bfSgjelinek B_FALSE) != Z_OK) 29357c478bd9Sstevel@tonic-gate return (Z_ERR); 2936ce28b40eSzt129084 if (verify_details(CMD_INSTALL, argv) != Z_OK) 29377c478bd9Sstevel@tonic-gate return (Z_ERR); 29387c478bd9Sstevel@tonic-gate 2939ff17c8bfSgjelinek if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) { 2940ff17c8bfSgjelinek zerror(gettext("another %s may have an operation in " 2941ff17c8bfSgjelinek "progress."), "zoneadm"); 29427c478bd9Sstevel@tonic-gate return (Z_ERR); 29437c478bd9Sstevel@tonic-gate } 29447c478bd9Sstevel@tonic-gate err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE); 29457c478bd9Sstevel@tonic-gate if (err != Z_OK) { 29467c478bd9Sstevel@tonic-gate errno = err; 29477c478bd9Sstevel@tonic-gate zperror2(target_zone, gettext("could not set state")); 29487c478bd9Sstevel@tonic-gate goto done; 29497c478bd9Sstevel@tonic-gate } 29507c478bd9Sstevel@tonic-gate 29519acbbeafSnn35248 create_zfs_zonepath(zonepath); 29527c478bd9Sstevel@tonic-gate } 29537c478bd9Sstevel@tonic-gate 2954c75cc341S status = do_subproc(cmdbuf); 29559acbbeafSnn35248 if ((subproc_err = 29569acbbeafSnn35248 subproc_status(gettext("brand-specific installation"), status, 29579acbbeafSnn35248 B_FALSE)) != ZONE_SUBPROC_OK) { 2958ff17c8bfSgjelinek if (subproc_err == ZONE_SUBPROC_USAGE && !brand_help) { 2959ff17c8bfSgjelinek sub_usage(SHELP_INSTALL, CMD_INSTALL); 2960ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 2961ff17c8bfSgjelinek return (Z_ERR); 2962ff17c8bfSgjelinek } 2963ad02e316Sbatschul errno = subproc_err; 29649acbbeafSnn35248 err = Z_ERR; 29657c478bd9Sstevel@tonic-gate goto done; 29669acbbeafSnn35248 } 29677c478bd9Sstevel@tonic-gate 2968ff17c8bfSgjelinek if (brand_help) 2969ff17c8bfSgjelinek return (Z_OK); 2970ff17c8bfSgjelinek 29717c478bd9Sstevel@tonic-gate if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) { 29727c478bd9Sstevel@tonic-gate errno = err; 29737c478bd9Sstevel@tonic-gate zperror2(target_zone, gettext("could not set state")); 29747c478bd9Sstevel@tonic-gate goto done; 29757c478bd9Sstevel@tonic-gate } 29767c478bd9Sstevel@tonic-gate 29771100f00dSgjelinek if (do_postinstall) { 29781100f00dSgjelinek status = do_subproc(postcmdbuf); 29791100f00dSgjelinek 29801100f00dSgjelinek if ((subproc_err = 29811100f00dSgjelinek subproc_status(gettext("brand-specific post-install"), 29821100f00dSgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) { 2983ad02e316Sbatschul errno = subproc_err; 29841100f00dSgjelinek err = Z_ERR; 29851100f00dSgjelinek (void) zone_set_state(target_zone, 29861100f00dSgjelinek ZONE_STATE_INCOMPLETE); 29871100f00dSgjelinek } 29881100f00dSgjelinek } 29891100f00dSgjelinek 29907c478bd9Sstevel@tonic-gate done: 29919acbbeafSnn35248 /* 2992ff17c8bfSgjelinek * If the install script exited with ZONE_SUBPROC_NOTCOMPLETE, try to 2993ff17c8bfSgjelinek * clean up the zone and leave the zone in the CONFIGURED state so that 2994ff17c8bfSgjelinek * another install can be attempted without requiring an uninstall 2995ff17c8bfSgjelinek * first. 29969acbbeafSnn35248 */ 2997ff17c8bfSgjelinek if (subproc_err == ZONE_SUBPROC_NOTCOMPLETE) { 2998ad02e316Sbatschul int temp_err; 2999ad02e316Sbatschul 3000ad02e316Sbatschul if ((temp_err = cleanup_zonepath(zonepath, B_FALSE)) != Z_OK) { 3001ad02e316Sbatschul errno = err = temp_err; 30029acbbeafSnn35248 zperror2(target_zone, 30039acbbeafSnn35248 gettext("cleaning up zonepath failed")); 3004ad02e316Sbatschul } else if ((temp_err = zone_set_state(target_zone, 30059acbbeafSnn35248 ZONE_STATE_CONFIGURED)) != Z_OK) { 3006ad02e316Sbatschul errno = err = temp_err; 30079acbbeafSnn35248 zperror2(target_zone, gettext("could not set state")); 30089acbbeafSnn35248 } 30099acbbeafSnn35248 } 30109acbbeafSnn35248 3011ff17c8bfSgjelinek if (!brand_help) 3012ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 30137c478bd9Sstevel@tonic-gate return ((err == Z_OK) ? Z_OK : Z_ERR); 30147c478bd9Sstevel@tonic-gate } 30157c478bd9Sstevel@tonic-gate 3016865e09a4Sgjelinek static void 3017865e09a4Sgjelinek warn_dev_match(zone_dochandle_t s_handle, char *source_zone, 3018865e09a4Sgjelinek zone_dochandle_t t_handle, char *target_zone) 3019865e09a4Sgjelinek { 3020865e09a4Sgjelinek int err; 3021865e09a4Sgjelinek struct zone_devtab s_devtab; 3022865e09a4Sgjelinek struct zone_devtab t_devtab; 3023865e09a4Sgjelinek 3024865e09a4Sgjelinek if ((err = zonecfg_setdevent(t_handle)) != Z_OK) { 3025865e09a4Sgjelinek errno = err; 3026865e09a4Sgjelinek zperror2(target_zone, gettext("could not enumerate devices")); 3027865e09a4Sgjelinek return; 3028865e09a4Sgjelinek } 3029865e09a4Sgjelinek 3030865e09a4Sgjelinek while (zonecfg_getdevent(t_handle, &t_devtab) == Z_OK) { 3031865e09a4Sgjelinek if ((err = zonecfg_setdevent(s_handle)) != Z_OK) { 3032865e09a4Sgjelinek errno = err; 3033865e09a4Sgjelinek zperror2(source_zone, 3034865e09a4Sgjelinek gettext("could not enumerate devices")); 3035865e09a4Sgjelinek (void) zonecfg_enddevent(t_handle); 3036865e09a4Sgjelinek return; 3037865e09a4Sgjelinek } 3038865e09a4Sgjelinek 3039865e09a4Sgjelinek while (zonecfg_getdevent(s_handle, &s_devtab) == Z_OK) { 3040865e09a4Sgjelinek /* 3041865e09a4Sgjelinek * Use fnmatch to catch the case where wildcards 3042865e09a4Sgjelinek * were used in one zone and the other has an 3043865e09a4Sgjelinek * explicit entry (e.g. /dev/dsk/c0t0d0s6 vs. 3044865e09a4Sgjelinek * /dev/\*dsk/c0t0d0s6). 3045865e09a4Sgjelinek */ 3046865e09a4Sgjelinek if (fnmatch(t_devtab.zone_dev_match, 3047865e09a4Sgjelinek s_devtab.zone_dev_match, FNM_PATHNAME) == 0 || 3048865e09a4Sgjelinek fnmatch(s_devtab.zone_dev_match, 3049865e09a4Sgjelinek t_devtab.zone_dev_match, FNM_PATHNAME) == 0) { 3050865e09a4Sgjelinek (void) fprintf(stderr, 3051865e09a4Sgjelinek gettext("WARNING: device '%s' " 3052865e09a4Sgjelinek "is configured in both zones.\n"), 3053865e09a4Sgjelinek t_devtab.zone_dev_match); 3054865e09a4Sgjelinek break; 3055865e09a4Sgjelinek } 3056865e09a4Sgjelinek } 3057865e09a4Sgjelinek (void) zonecfg_enddevent(s_handle); 3058865e09a4Sgjelinek } 3059865e09a4Sgjelinek 3060865e09a4Sgjelinek (void) zonecfg_enddevent(t_handle); 3061865e09a4Sgjelinek } 3062865e09a4Sgjelinek 3063865e09a4Sgjelinek /* 3064865e09a4Sgjelinek * Check if the specified mount option (opt) is contained within the 3065865e09a4Sgjelinek * options string. 3066865e09a4Sgjelinek */ 3067865e09a4Sgjelinek static boolean_t 3068865e09a4Sgjelinek opt_match(char *opt, char *options) 3069865e09a4Sgjelinek { 3070865e09a4Sgjelinek char *p; 3071865e09a4Sgjelinek char *lastp; 3072865e09a4Sgjelinek 3073865e09a4Sgjelinek if ((p = strtok_r(options, ",", &lastp)) != NULL) { 3074865e09a4Sgjelinek if (strcmp(p, opt) == 0) 3075865e09a4Sgjelinek return (B_TRUE); 3076865e09a4Sgjelinek while ((p = strtok_r(NULL, ",", &lastp)) != NULL) { 3077865e09a4Sgjelinek if (strcmp(p, opt) == 0) 3078865e09a4Sgjelinek return (B_TRUE); 3079865e09a4Sgjelinek } 3080865e09a4Sgjelinek } 3081865e09a4Sgjelinek 3082865e09a4Sgjelinek return (B_FALSE); 3083865e09a4Sgjelinek } 3084865e09a4Sgjelinek 30850b5de56dSgjelinek #define RW_LOFS "WARNING: read-write lofs file system on '%s' is configured " \ 3086865e09a4Sgjelinek "in both zones.\n" 3087865e09a4Sgjelinek 3088865e09a4Sgjelinek static void 3089865e09a4Sgjelinek print_fs_warnings(struct zone_fstab *s_fstab, struct zone_fstab *t_fstab) 3090865e09a4Sgjelinek { 3091865e09a4Sgjelinek /* 3092865e09a4Sgjelinek * It is ok to have shared lofs mounted fs but we want to warn if 3093865e09a4Sgjelinek * either is rw since this will effect the other zone. 3094865e09a4Sgjelinek */ 3095865e09a4Sgjelinek if (strcmp(t_fstab->zone_fs_type, "lofs") == 0) { 3096865e09a4Sgjelinek zone_fsopt_t *optp; 3097865e09a4Sgjelinek 3098865e09a4Sgjelinek /* The default is rw so no options means rw */ 3099865e09a4Sgjelinek if (t_fstab->zone_fs_options == NULL || 3100865e09a4Sgjelinek s_fstab->zone_fs_options == NULL) { 3101865e09a4Sgjelinek (void) fprintf(stderr, gettext(RW_LOFS), 3102865e09a4Sgjelinek t_fstab->zone_fs_special); 3103865e09a4Sgjelinek return; 3104865e09a4Sgjelinek } 3105865e09a4Sgjelinek 3106865e09a4Sgjelinek for (optp = s_fstab->zone_fs_options; optp != NULL; 3107865e09a4Sgjelinek optp = optp->zone_fsopt_next) { 3108865e09a4Sgjelinek if (opt_match("rw", optp->zone_fsopt_opt)) { 3109865e09a4Sgjelinek (void) fprintf(stderr, gettext(RW_LOFS), 3110865e09a4Sgjelinek s_fstab->zone_fs_special); 3111865e09a4Sgjelinek return; 3112865e09a4Sgjelinek } 3113865e09a4Sgjelinek } 3114865e09a4Sgjelinek 3115865e09a4Sgjelinek for (optp = t_fstab->zone_fs_options; optp != NULL; 3116865e09a4Sgjelinek optp = optp->zone_fsopt_next) { 3117865e09a4Sgjelinek if (opt_match("rw", optp->zone_fsopt_opt)) { 3118865e09a4Sgjelinek (void) fprintf(stderr, gettext(RW_LOFS), 3119865e09a4Sgjelinek t_fstab->zone_fs_special); 3120865e09a4Sgjelinek return; 3121865e09a4Sgjelinek } 3122865e09a4Sgjelinek } 3123865e09a4Sgjelinek 3124865e09a4Sgjelinek return; 3125865e09a4Sgjelinek } 3126865e09a4Sgjelinek 3127865e09a4Sgjelinek /* 3128865e09a4Sgjelinek * TRANSLATION_NOTE 31290b5de56dSgjelinek * The first variable is the file system type and the second is 31300b5de56dSgjelinek * the file system special device. For example, 31310b5de56dSgjelinek * WARNING: ufs file system on '/dev/dsk/c0t0d0s0' ... 3132865e09a4Sgjelinek */ 31330b5de56dSgjelinek (void) fprintf(stderr, gettext("WARNING: %s file system on '%s' " 3134865e09a4Sgjelinek "is configured in both zones.\n"), t_fstab->zone_fs_type, 3135865e09a4Sgjelinek t_fstab->zone_fs_special); 3136865e09a4Sgjelinek } 3137865e09a4Sgjelinek 3138865e09a4Sgjelinek static void 3139865e09a4Sgjelinek warn_fs_match(zone_dochandle_t s_handle, char *source_zone, 3140865e09a4Sgjelinek zone_dochandle_t t_handle, char *target_zone) 3141865e09a4Sgjelinek { 3142865e09a4Sgjelinek int err; 3143865e09a4Sgjelinek struct zone_fstab s_fstab; 3144865e09a4Sgjelinek struct zone_fstab t_fstab; 3145865e09a4Sgjelinek 3146865e09a4Sgjelinek if ((err = zonecfg_setfsent(t_handle)) != Z_OK) { 3147865e09a4Sgjelinek errno = err; 3148865e09a4Sgjelinek zperror2(target_zone, 31490b5de56dSgjelinek gettext("could not enumerate file systems")); 3150865e09a4Sgjelinek return; 3151865e09a4Sgjelinek } 3152865e09a4Sgjelinek 3153865e09a4Sgjelinek while (zonecfg_getfsent(t_handle, &t_fstab) == Z_OK) { 3154865e09a4Sgjelinek if ((err = zonecfg_setfsent(s_handle)) != Z_OK) { 3155865e09a4Sgjelinek errno = err; 3156865e09a4Sgjelinek zperror2(source_zone, 31570b5de56dSgjelinek gettext("could not enumerate file systems")); 3158865e09a4Sgjelinek (void) zonecfg_endfsent(t_handle); 3159865e09a4Sgjelinek return; 3160865e09a4Sgjelinek } 3161865e09a4Sgjelinek 3162865e09a4Sgjelinek while (zonecfg_getfsent(s_handle, &s_fstab) == Z_OK) { 3163865e09a4Sgjelinek if (strcmp(t_fstab.zone_fs_special, 3164865e09a4Sgjelinek s_fstab.zone_fs_special) == 0) { 3165865e09a4Sgjelinek print_fs_warnings(&s_fstab, &t_fstab); 3166865e09a4Sgjelinek break; 3167865e09a4Sgjelinek } 3168865e09a4Sgjelinek } 3169865e09a4Sgjelinek (void) zonecfg_endfsent(s_handle); 3170865e09a4Sgjelinek } 3171865e09a4Sgjelinek 3172865e09a4Sgjelinek (void) zonecfg_endfsent(t_handle); 3173865e09a4Sgjelinek } 3174865e09a4Sgjelinek 3175865e09a4Sgjelinek /* 3176865e09a4Sgjelinek * We don't catch the case where you used the same IP address but 3177865e09a4Sgjelinek * it is not an exact string match. For example, 192.9.0.128 vs. 192.09.0.128. 3178865e09a4Sgjelinek * However, we're not going to worry about that but we will check for 3179865e09a4Sgjelinek * a possible netmask on one of the addresses (e.g. 10.0.0.1 and 10.0.0.1/24) 3180865e09a4Sgjelinek * and handle that case as a match. 3181865e09a4Sgjelinek */ 3182865e09a4Sgjelinek static void 3183865e09a4Sgjelinek warn_ip_match(zone_dochandle_t s_handle, char *source_zone, 3184865e09a4Sgjelinek zone_dochandle_t t_handle, char *target_zone) 3185865e09a4Sgjelinek { 3186865e09a4Sgjelinek int err; 3187865e09a4Sgjelinek struct zone_nwiftab s_nwiftab; 3188865e09a4Sgjelinek struct zone_nwiftab t_nwiftab; 3189865e09a4Sgjelinek 3190865e09a4Sgjelinek if ((err = zonecfg_setnwifent(t_handle)) != Z_OK) { 3191865e09a4Sgjelinek errno = err; 3192865e09a4Sgjelinek zperror2(target_zone, 3193865e09a4Sgjelinek gettext("could not enumerate network interfaces")); 3194865e09a4Sgjelinek return; 3195865e09a4Sgjelinek } 3196865e09a4Sgjelinek 3197865e09a4Sgjelinek while (zonecfg_getnwifent(t_handle, &t_nwiftab) == Z_OK) { 3198865e09a4Sgjelinek char *p; 3199865e09a4Sgjelinek 3200865e09a4Sgjelinek /* remove an (optional) netmask from the address */ 3201865e09a4Sgjelinek if ((p = strchr(t_nwiftab.zone_nwif_address, '/')) != NULL) 3202865e09a4Sgjelinek *p = '\0'; 3203865e09a4Sgjelinek 3204865e09a4Sgjelinek if ((err = zonecfg_setnwifent(s_handle)) != Z_OK) { 3205865e09a4Sgjelinek errno = err; 3206865e09a4Sgjelinek zperror2(source_zone, 3207865e09a4Sgjelinek gettext("could not enumerate network interfaces")); 3208865e09a4Sgjelinek (void) zonecfg_endnwifent(t_handle); 3209865e09a4Sgjelinek return; 3210865e09a4Sgjelinek } 3211865e09a4Sgjelinek 3212865e09a4Sgjelinek while (zonecfg_getnwifent(s_handle, &s_nwiftab) == Z_OK) { 3213865e09a4Sgjelinek /* remove an (optional) netmask from the address */ 3214865e09a4Sgjelinek if ((p = strchr(s_nwiftab.zone_nwif_address, '/')) 3215865e09a4Sgjelinek != NULL) 3216865e09a4Sgjelinek *p = '\0'; 3217865e09a4Sgjelinek 3218f4b3ec61Sdh155122 /* For exclusive-IP zones, address is not specified. */ 3219f4b3ec61Sdh155122 if (strlen(s_nwiftab.zone_nwif_address) == 0) 3220f4b3ec61Sdh155122 continue; 3221f4b3ec61Sdh155122 3222865e09a4Sgjelinek if (strcmp(t_nwiftab.zone_nwif_address, 3223865e09a4Sgjelinek s_nwiftab.zone_nwif_address) == 0) { 3224865e09a4Sgjelinek (void) fprintf(stderr, 3225865e09a4Sgjelinek gettext("WARNING: network address '%s' " 3226865e09a4Sgjelinek "is configured in both zones.\n"), 3227865e09a4Sgjelinek t_nwiftab.zone_nwif_address); 3228865e09a4Sgjelinek break; 3229865e09a4Sgjelinek } 3230865e09a4Sgjelinek } 3231865e09a4Sgjelinek (void) zonecfg_endnwifent(s_handle); 3232865e09a4Sgjelinek } 3233865e09a4Sgjelinek 3234865e09a4Sgjelinek (void) zonecfg_endnwifent(t_handle); 3235865e09a4Sgjelinek } 3236865e09a4Sgjelinek 3237865e09a4Sgjelinek static void 32389acbbeafSnn35248 warn_dataset_match(zone_dochandle_t s_handle, char *source, 32399acbbeafSnn35248 zone_dochandle_t t_handle, char *target) 3240865e09a4Sgjelinek { 3241865e09a4Sgjelinek int err; 3242865e09a4Sgjelinek struct zone_dstab s_dstab; 3243865e09a4Sgjelinek struct zone_dstab t_dstab; 3244865e09a4Sgjelinek 3245865e09a4Sgjelinek if ((err = zonecfg_setdsent(t_handle)) != Z_OK) { 3246865e09a4Sgjelinek errno = err; 32479acbbeafSnn35248 zperror2(target, gettext("could not enumerate datasets")); 3248865e09a4Sgjelinek return; 3249865e09a4Sgjelinek } 3250865e09a4Sgjelinek 3251865e09a4Sgjelinek while (zonecfg_getdsent(t_handle, &t_dstab) == Z_OK) { 3252865e09a4Sgjelinek if ((err = zonecfg_setdsent(s_handle)) != Z_OK) { 3253865e09a4Sgjelinek errno = err; 32549acbbeafSnn35248 zperror2(source, 3255865e09a4Sgjelinek gettext("could not enumerate datasets")); 3256865e09a4Sgjelinek (void) zonecfg_enddsent(t_handle); 3257865e09a4Sgjelinek return; 3258865e09a4Sgjelinek } 3259865e09a4Sgjelinek 3260865e09a4Sgjelinek while (zonecfg_getdsent(s_handle, &s_dstab) == Z_OK) { 3261865e09a4Sgjelinek if (strcmp(t_dstab.zone_dataset_name, 3262865e09a4Sgjelinek s_dstab.zone_dataset_name) == 0) { 32639acbbeafSnn35248 target_zone = source; 32649acbbeafSnn35248 zerror(gettext("WARNING: dataset '%s' " 3265865e09a4Sgjelinek "is configured in both zones.\n"), 3266865e09a4Sgjelinek t_dstab.zone_dataset_name); 3267865e09a4Sgjelinek break; 3268865e09a4Sgjelinek } 3269865e09a4Sgjelinek } 3270865e09a4Sgjelinek (void) zonecfg_enddsent(s_handle); 3271865e09a4Sgjelinek } 3272865e09a4Sgjelinek 3273865e09a4Sgjelinek (void) zonecfg_enddsent(t_handle); 3274865e09a4Sgjelinek } 3275865e09a4Sgjelinek 32769acbbeafSnn35248 /* 32779acbbeafSnn35248 * Check that the clone and its source have the same brand type. 32789acbbeafSnn35248 */ 32799acbbeafSnn35248 static int 32809acbbeafSnn35248 valid_brand_clone(char *source_zone, char *target_zone) 32819acbbeafSnn35248 { 3282123807fbSedp brand_handle_t bh; 32839acbbeafSnn35248 char source_brand[MAXNAMELEN]; 32849acbbeafSnn35248 32859acbbeafSnn35248 if ((zone_get_brand(source_zone, source_brand, 32869acbbeafSnn35248 sizeof (source_brand))) != Z_OK) { 32879acbbeafSnn35248 (void) fprintf(stderr, "%s: zone '%s': %s\n", 32889acbbeafSnn35248 execname, source_zone, gettext("missing or invalid brand")); 32899acbbeafSnn35248 return (Z_ERR); 32909acbbeafSnn35248 } 32919acbbeafSnn35248 3292ad02e316Sbatschul if (strcmp(source_brand, target_brand) != 0) { 32939acbbeafSnn35248 (void) fprintf(stderr, 32949acbbeafSnn35248 gettext("%s: Zones '%s' and '%s' have different brand " 32959acbbeafSnn35248 "types.\n"), execname, source_zone, target_zone); 32969acbbeafSnn35248 return (Z_ERR); 32979acbbeafSnn35248 } 32989acbbeafSnn35248 3299123807fbSedp if ((bh = brand_open(target_brand)) == NULL) { 33009acbbeafSnn35248 zerror(gettext("missing or invalid brand")); 33019acbbeafSnn35248 return (Z_ERR); 33029acbbeafSnn35248 } 3303123807fbSedp brand_close(bh); 33049acbbeafSnn35248 return (Z_OK); 33059acbbeafSnn35248 } 33069acbbeafSnn35248 3307865e09a4Sgjelinek static int 3308865e09a4Sgjelinek validate_clone(char *source_zone, char *target_zone) 3309865e09a4Sgjelinek { 3310865e09a4Sgjelinek int err = Z_OK; 3311865e09a4Sgjelinek zone_dochandle_t s_handle; 3312865e09a4Sgjelinek zone_dochandle_t t_handle; 3313865e09a4Sgjelinek 3314865e09a4Sgjelinek if ((t_handle = zonecfg_init_handle()) == NULL) { 3315865e09a4Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3316865e09a4Sgjelinek return (Z_ERR); 3317865e09a4Sgjelinek } 3318865e09a4Sgjelinek if ((err = zonecfg_get_handle(target_zone, t_handle)) != Z_OK) { 3319865e09a4Sgjelinek errno = err; 3320865e09a4Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3321865e09a4Sgjelinek zonecfg_fini_handle(t_handle); 3322865e09a4Sgjelinek return (Z_ERR); 3323865e09a4Sgjelinek } 3324865e09a4Sgjelinek 3325865e09a4Sgjelinek if ((s_handle = zonecfg_init_handle()) == NULL) { 3326865e09a4Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3327865e09a4Sgjelinek zonecfg_fini_handle(t_handle); 3328865e09a4Sgjelinek return (Z_ERR); 3329865e09a4Sgjelinek } 3330865e09a4Sgjelinek if ((err = zonecfg_get_handle(source_zone, s_handle)) != Z_OK) { 3331865e09a4Sgjelinek errno = err; 3332865e09a4Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 3333865e09a4Sgjelinek goto done; 3334865e09a4Sgjelinek } 3335865e09a4Sgjelinek 33369acbbeafSnn35248 /* verify new zone has same brand type */ 33379acbbeafSnn35248 err = valid_brand_clone(source_zone, target_zone); 33389acbbeafSnn35248 if (err != Z_OK) 33399acbbeafSnn35248 goto done; 33409acbbeafSnn35248 3341865e09a4Sgjelinek /* warn about imported fs's which are the same */ 3342865e09a4Sgjelinek warn_fs_match(s_handle, source_zone, t_handle, target_zone); 3343865e09a4Sgjelinek 3344865e09a4Sgjelinek /* warn about imported IP addresses which are the same */ 3345865e09a4Sgjelinek warn_ip_match(s_handle, source_zone, t_handle, target_zone); 3346865e09a4Sgjelinek 3347865e09a4Sgjelinek /* warn about imported devices which are the same */ 3348865e09a4Sgjelinek warn_dev_match(s_handle, source_zone, t_handle, target_zone); 3349865e09a4Sgjelinek 3350865e09a4Sgjelinek /* warn about imported datasets which are the same */ 3351865e09a4Sgjelinek warn_dataset_match(s_handle, source_zone, t_handle, target_zone); 3352865e09a4Sgjelinek 3353865e09a4Sgjelinek done: 3354865e09a4Sgjelinek zonecfg_fini_handle(t_handle); 3355865e09a4Sgjelinek zonecfg_fini_handle(s_handle); 3356865e09a4Sgjelinek 3357865e09a4Sgjelinek return ((err == Z_OK) ? Z_OK : Z_ERR); 3358865e09a4Sgjelinek } 3359865e09a4Sgjelinek 3360865e09a4Sgjelinek static int 3361865e09a4Sgjelinek copy_zone(char *src, char *dst) 3362865e09a4Sgjelinek { 3363865e09a4Sgjelinek boolean_t out_null = B_FALSE; 3364865e09a4Sgjelinek int status; 3365865e09a4Sgjelinek char *outfile; 3366865e09a4Sgjelinek char cmdbuf[MAXPATHLEN * 2 + 128]; 3367865e09a4Sgjelinek 3368865e09a4Sgjelinek if ((outfile = tempnam("/var/log", "zone")) == NULL) { 3369865e09a4Sgjelinek outfile = "/dev/null"; 3370865e09a4Sgjelinek out_null = B_TRUE; 3371865e09a4Sgjelinek } 3372865e09a4Sgjelinek 33730b5de56dSgjelinek /* 33740b5de56dSgjelinek * Use find to get the list of files to copy. We need to skip 33750b5de56dSgjelinek * files of type "socket" since cpio can't handle those but that 33760b5de56dSgjelinek * should be ok since the app will recreate the socket when it runs. 33770b5de56dSgjelinek * We also need to filter out anything under the .zfs subdir. Since 33780b5de56dSgjelinek * find is running depth-first, we need the extra egrep to filter .zfs. 33790b5de56dSgjelinek */ 3380865e09a4Sgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), 33810b5de56dSgjelinek "cd %s && /usr/bin/find . -type s -prune -o -depth -print | " 338207b574eeSgjelinek "/usr/bin/egrep -v '^\\./\\.zfs$|^\\./\\.zfs/' | " 3383865e09a4Sgjelinek "/usr/bin/cpio -pdmuP@ %s > %s 2>&1", 3384865e09a4Sgjelinek src, dst, outfile); 3385865e09a4Sgjelinek 3386865e09a4Sgjelinek status = do_subproc(cmdbuf); 3387865e09a4Sgjelinek 33889acbbeafSnn35248 if (subproc_status("copy", status, B_TRUE) != ZONE_SUBPROC_OK) { 3389865e09a4Sgjelinek if (!out_null) 3390865e09a4Sgjelinek (void) fprintf(stderr, gettext("\nThe copy failed.\n" 3391865e09a4Sgjelinek "More information can be found in %s\n"), outfile); 33929acbbeafSnn35248 return (Z_ERR); 3393865e09a4Sgjelinek } 3394865e09a4Sgjelinek 3395865e09a4Sgjelinek if (!out_null) 3396865e09a4Sgjelinek (void) unlink(outfile); 3397865e09a4Sgjelinek 3398865e09a4Sgjelinek return (Z_OK); 3399865e09a4Sgjelinek } 3400865e09a4Sgjelinek 3401865e09a4Sgjelinek /* ARGSUSED */ 34020094b373Sjv227347 int 34030094b373Sjv227347 zfm_print(const struct mnttab *p, void *r) { 34040094b373Sjv227347 zerror(" %s\n", p->mnt_mountp); 3405865e09a4Sgjelinek return (0); 3406865e09a4Sgjelinek } 3407865e09a4Sgjelinek 34080b5de56dSgjelinek int 34090b5de56dSgjelinek clone_copy(char *source_zonepath, char *zonepath) 34100b5de56dSgjelinek { 34110b5de56dSgjelinek int err; 34120b5de56dSgjelinek 34130b5de56dSgjelinek /* Don't clone the zone if anything is still mounted there */ 34140b5de56dSgjelinek if (zonecfg_find_mounts(source_zonepath, NULL, NULL)) { 34150b5de56dSgjelinek zerror(gettext("These file systems are mounted on " 34160b5de56dSgjelinek "subdirectories of %s.\n"), source_zonepath); 34170b5de56dSgjelinek (void) zonecfg_find_mounts(source_zonepath, zfm_print, NULL); 34180b5de56dSgjelinek return (Z_ERR); 34190b5de56dSgjelinek } 34200b5de56dSgjelinek 34210b5de56dSgjelinek /* 34220b5de56dSgjelinek * Attempt to create a ZFS fs for the zonepath. As usual, we don't 34230b5de56dSgjelinek * care if this works or not since we always have the default behavior 34240b5de56dSgjelinek * of a simple directory for the zonepath. 34250b5de56dSgjelinek */ 34260b5de56dSgjelinek create_zfs_zonepath(zonepath); 34270b5de56dSgjelinek 34280b5de56dSgjelinek (void) printf(gettext("Copying %s..."), source_zonepath); 34290b5de56dSgjelinek (void) fflush(stdout); 34300b5de56dSgjelinek 34310b5de56dSgjelinek err = copy_zone(source_zonepath, zonepath); 34320b5de56dSgjelinek 34330b5de56dSgjelinek (void) printf("\n"); 34340b5de56dSgjelinek 34350b5de56dSgjelinek return (err); 34360b5de56dSgjelinek } 34370b5de56dSgjelinek 3438865e09a4Sgjelinek static int 3439865e09a4Sgjelinek clone_func(int argc, char *argv[]) 3440865e09a4Sgjelinek { 3441865e09a4Sgjelinek char *source_zone = NULL; 3442865e09a4Sgjelinek int lockfd; 3443865e09a4Sgjelinek int err, arg; 3444865e09a4Sgjelinek char zonepath[MAXPATHLEN]; 3445865e09a4Sgjelinek char source_zonepath[MAXPATHLEN]; 3446865e09a4Sgjelinek zone_state_t state; 3447865e09a4Sgjelinek zone_entry_t *zent; 34480b5de56dSgjelinek char *method = NULL; 34490b5de56dSgjelinek char *snapshot = NULL; 3450ff17c8bfSgjelinek char cmdbuf[MAXPATHLEN]; 3451ff17c8bfSgjelinek char postcmdbuf[MAXPATHLEN]; 3452ff17c8bfSgjelinek char presnapbuf[MAXPATHLEN]; 3453ff17c8bfSgjelinek char postsnapbuf[MAXPATHLEN]; 3454ff17c8bfSgjelinek char validsnapbuf[MAXPATHLEN]; 3455ff17c8bfSgjelinek brand_handle_t bh = NULL; 3456ff17c8bfSgjelinek int status; 3457ff17c8bfSgjelinek boolean_t brand_help = B_FALSE; 3458865e09a4Sgjelinek 3459865e09a4Sgjelinek if (zonecfg_in_alt_root()) { 3460865e09a4Sgjelinek zerror(gettext("cannot clone zone in alternate root")); 3461865e09a4Sgjelinek return (Z_ERR); 3462865e09a4Sgjelinek } 3463865e09a4Sgjelinek 3464ff17c8bfSgjelinek /* Check the argv string for args we handle internally */ 3465865e09a4Sgjelinek optind = 0; 3466ff17c8bfSgjelinek opterr = 0; 3467ff17c8bfSgjelinek while ((arg = getopt(argc, argv, "?m:s:")) != EOF) { 3468865e09a4Sgjelinek switch (arg) { 3469865e09a4Sgjelinek case '?': 3470ff17c8bfSgjelinek if (optopt == '?') { 3471865e09a4Sgjelinek sub_usage(SHELP_CLONE, CMD_CLONE); 3472ff17c8bfSgjelinek brand_help = B_TRUE; 3473ff17c8bfSgjelinek } 3474ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 3475ff17c8bfSgjelinek break; 3476865e09a4Sgjelinek case 'm': 3477865e09a4Sgjelinek method = optarg; 3478865e09a4Sgjelinek break; 34790b5de56dSgjelinek case 's': 34800b5de56dSgjelinek snapshot = optarg; 34810b5de56dSgjelinek break; 3482865e09a4Sgjelinek default: 3483ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 3484ff17c8bfSgjelinek break; 3485ff17c8bfSgjelinek } 3486ff17c8bfSgjelinek } 3487ff17c8bfSgjelinek 3488ff17c8bfSgjelinek if (argc != (optind + 1)) { 3489865e09a4Sgjelinek sub_usage(SHELP_CLONE, CMD_CLONE); 3490865e09a4Sgjelinek return (Z_USAGE); 3491865e09a4Sgjelinek } 3492ff17c8bfSgjelinek 3493865e09a4Sgjelinek source_zone = argv[optind]; 3494ff17c8bfSgjelinek 3495ff17c8bfSgjelinek if (!brand_help) { 3496ff17c8bfSgjelinek if (sanity_check(target_zone, CMD_CLONE, B_FALSE, B_TRUE, 3497ff17c8bfSgjelinek B_FALSE) != Z_OK) 3498865e09a4Sgjelinek return (Z_ERR); 3499ce28b40eSzt129084 if (verify_details(CMD_CLONE, argv) != Z_OK) 3500865e09a4Sgjelinek return (Z_ERR); 3501865e09a4Sgjelinek 3502865e09a4Sgjelinek /* 3503865e09a4Sgjelinek * We also need to do some extra validation on the source zone. 3504865e09a4Sgjelinek */ 3505865e09a4Sgjelinek if (strcmp(source_zone, GLOBAL_ZONENAME) == 0) { 3506ff17c8bfSgjelinek zerror(gettext("%s operation is invalid for the " 3507ff17c8bfSgjelinek "global zone."), cmd_to_str(CMD_CLONE)); 3508865e09a4Sgjelinek return (Z_ERR); 3509865e09a4Sgjelinek } 3510865e09a4Sgjelinek 3511865e09a4Sgjelinek if (strncmp(source_zone, "SUNW", 4) == 0) { 3512ff17c8bfSgjelinek zerror(gettext("%s operation is invalid for zones " 3513ff17c8bfSgjelinek "starting with SUNW."), cmd_to_str(CMD_CLONE)); 3514865e09a4Sgjelinek return (Z_ERR); 3515865e09a4Sgjelinek } 3516865e09a4Sgjelinek 3517cb8a054bSGlenn Faden if (auth_check(username, source_zone, SOURCE_ZONE) == Z_ERR) { 3518cb8a054bSGlenn Faden zerror(gettext("%s operation is invalid because " 3519cb8a054bSGlenn Faden "user is not authorized to read source zone."), 3520cb8a054bSGlenn Faden cmd_to_str(CMD_CLONE)); 3521cb8a054bSGlenn Faden return (Z_ERR); 3522cb8a054bSGlenn Faden } 3523cb8a054bSGlenn Faden 3524865e09a4Sgjelinek zent = lookup_running_zone(source_zone); 3525865e09a4Sgjelinek if (zent != NULL) { 3526865e09a4Sgjelinek /* check whether the zone is ready or running */ 3527ff17c8bfSgjelinek if ((err = zone_get_state(zent->zname, 3528ff17c8bfSgjelinek &zent->zstate_num)) != Z_OK) { 3529865e09a4Sgjelinek errno = err; 3530ff17c8bfSgjelinek zperror2(zent->zname, gettext("could not get " 3531ff17c8bfSgjelinek "state")); 3532865e09a4Sgjelinek /* can't tell, so hedge */ 3533865e09a4Sgjelinek zent->zstate_str = "ready/running"; 3534865e09a4Sgjelinek } else { 3535ff17c8bfSgjelinek zent->zstate_str = 3536ff17c8bfSgjelinek zone_state_str(zent->zstate_num); 3537865e09a4Sgjelinek } 3538865e09a4Sgjelinek zerror(gettext("%s operation is invalid for %s zones."), 3539865e09a4Sgjelinek cmd_to_str(CMD_CLONE), zent->zstate_str); 3540865e09a4Sgjelinek return (Z_ERR); 3541865e09a4Sgjelinek } 3542865e09a4Sgjelinek 3543865e09a4Sgjelinek if ((err = zone_get_state(source_zone, &state)) != Z_OK) { 3544865e09a4Sgjelinek errno = err; 3545865e09a4Sgjelinek zperror2(source_zone, gettext("could not get state")); 3546865e09a4Sgjelinek return (Z_ERR); 3547865e09a4Sgjelinek } 3548865e09a4Sgjelinek if (state != ZONE_STATE_INSTALLED) { 3549865e09a4Sgjelinek (void) fprintf(stderr, 3550865e09a4Sgjelinek gettext("%s: zone %s is %s; %s is required.\n"), 3551865e09a4Sgjelinek execname, source_zone, zone_state_str(state), 3552865e09a4Sgjelinek zone_state_str(ZONE_STATE_INSTALLED)); 3553865e09a4Sgjelinek return (Z_ERR); 3554865e09a4Sgjelinek } 3555865e09a4Sgjelinek 3556865e09a4Sgjelinek /* 3557865e09a4Sgjelinek * The source zone checks out ok, continue with the clone. 3558865e09a4Sgjelinek */ 3559865e09a4Sgjelinek 3560865e09a4Sgjelinek if (validate_clone(source_zone, target_zone) != Z_OK) 3561865e09a4Sgjelinek return (Z_ERR); 3562865e09a4Sgjelinek 3563ff17c8bfSgjelinek if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) { 3564ff17c8bfSgjelinek zerror(gettext("another %s may have an operation in " 3565ff17c8bfSgjelinek "progress."), "zoneadm"); 3566865e09a4Sgjelinek return (Z_ERR); 3567865e09a4Sgjelinek } 3568ff17c8bfSgjelinek } 3569865e09a4Sgjelinek 3570865e09a4Sgjelinek if ((err = zone_get_zonepath(source_zone, source_zonepath, 3571865e09a4Sgjelinek sizeof (source_zonepath))) != Z_OK) { 3572865e09a4Sgjelinek errno = err; 3573865e09a4Sgjelinek zperror2(source_zone, gettext("could not get zone path")); 3574865e09a4Sgjelinek goto done; 3575865e09a4Sgjelinek } 3576865e09a4Sgjelinek 3577865e09a4Sgjelinek if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath))) 3578865e09a4Sgjelinek != Z_OK) { 3579865e09a4Sgjelinek errno = err; 3580865e09a4Sgjelinek zperror2(target_zone, gettext("could not get zone path")); 3581865e09a4Sgjelinek goto done; 3582865e09a4Sgjelinek } 3583865e09a4Sgjelinek 3584ff17c8bfSgjelinek /* 3585ff17c8bfSgjelinek * Fetch the clone and postclone hooks from the brand configuration. 3586ff17c8bfSgjelinek */ 3587ff17c8bfSgjelinek if ((bh = brand_open(target_brand)) == NULL) { 3588ff17c8bfSgjelinek zerror(gettext("missing or invalid brand")); 3589ff17c8bfSgjelinek err = Z_ERR; 3590ff17c8bfSgjelinek goto done; 3591ff17c8bfSgjelinek } 3592ff17c8bfSgjelinek 3593ff17c8bfSgjelinek if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_clone, target_zone, 3594ff17c8bfSgjelinek zonepath) != Z_OK) { 3595ff17c8bfSgjelinek zerror("invalid brand configuration: missing clone resource"); 3596ff17c8bfSgjelinek brand_close(bh); 3597ff17c8bfSgjelinek err = Z_ERR; 3598ff17c8bfSgjelinek goto done; 3599ff17c8bfSgjelinek } 3600ff17c8bfSgjelinek 3601ff17c8bfSgjelinek if (get_hook(bh, postcmdbuf, sizeof (postcmdbuf), brand_get_postclone, 3602ff17c8bfSgjelinek target_zone, zonepath) != Z_OK) { 3603ff17c8bfSgjelinek zerror("invalid brand configuration: missing postclone " 3604ff17c8bfSgjelinek "resource"); 3605ff17c8bfSgjelinek brand_close(bh); 3606ff17c8bfSgjelinek err = Z_ERR; 3607ff17c8bfSgjelinek goto done; 3608ff17c8bfSgjelinek } 3609ff17c8bfSgjelinek 3610ff17c8bfSgjelinek if (get_hook(bh, presnapbuf, sizeof (presnapbuf), brand_get_presnap, 3611ff17c8bfSgjelinek source_zone, source_zonepath) != Z_OK) { 3612ff17c8bfSgjelinek zerror("invalid brand configuration: missing presnap " 3613ff17c8bfSgjelinek "resource"); 3614ff17c8bfSgjelinek brand_close(bh); 3615ff17c8bfSgjelinek err = Z_ERR; 3616ff17c8bfSgjelinek goto done; 3617ff17c8bfSgjelinek } 3618ff17c8bfSgjelinek 3619ff17c8bfSgjelinek if (get_hook(bh, postsnapbuf, sizeof (postsnapbuf), brand_get_postsnap, 3620ff17c8bfSgjelinek source_zone, source_zonepath) != Z_OK) { 3621ff17c8bfSgjelinek zerror("invalid brand configuration: missing postsnap " 3622ff17c8bfSgjelinek "resource"); 3623ff17c8bfSgjelinek brand_close(bh); 3624ff17c8bfSgjelinek err = Z_ERR; 3625ff17c8bfSgjelinek goto done; 3626ff17c8bfSgjelinek } 3627ff17c8bfSgjelinek 3628ff17c8bfSgjelinek if (get_hook(bh, validsnapbuf, sizeof (validsnapbuf), 3629ff17c8bfSgjelinek brand_get_validatesnap, target_zone, zonepath) != Z_OK) { 3630ff17c8bfSgjelinek zerror("invalid brand configuration: missing validatesnap " 3631ff17c8bfSgjelinek "resource"); 3632ff17c8bfSgjelinek brand_close(bh); 3633ff17c8bfSgjelinek err = Z_ERR; 3634ff17c8bfSgjelinek goto done; 3635ff17c8bfSgjelinek } 3636ff17c8bfSgjelinek brand_close(bh); 3637ff17c8bfSgjelinek 3638ff17c8bfSgjelinek /* Append all options to clone hook. */ 3639ff17c8bfSgjelinek if (addoptions(cmdbuf, argv, sizeof (cmdbuf)) != Z_OK) { 3640ff17c8bfSgjelinek err = Z_ERR; 3641ff17c8bfSgjelinek goto done; 3642ff17c8bfSgjelinek } 3643ff17c8bfSgjelinek 3644ff17c8bfSgjelinek /* Append all options to postclone hook. */ 3645ff17c8bfSgjelinek if (addoptions(postcmdbuf, argv, sizeof (postcmdbuf)) != Z_OK) { 3646ff17c8bfSgjelinek err = Z_ERR; 3647ff17c8bfSgjelinek goto done; 3648ff17c8bfSgjelinek } 3649ff17c8bfSgjelinek 3650ff17c8bfSgjelinek if (!brand_help) { 3651865e09a4Sgjelinek if ((err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE)) 3652865e09a4Sgjelinek != Z_OK) { 3653865e09a4Sgjelinek errno = err; 3654865e09a4Sgjelinek zperror2(target_zone, gettext("could not set state")); 3655865e09a4Sgjelinek goto done; 3656865e09a4Sgjelinek } 3657ff17c8bfSgjelinek } 3658ff17c8bfSgjelinek 3659ff17c8bfSgjelinek /* 3660ff17c8bfSgjelinek * The clone hook is optional. If it exists, use the hook for 3661ff17c8bfSgjelinek * cloning, otherwise use the built-in clone support 3662ff17c8bfSgjelinek */ 3663ff17c8bfSgjelinek if (cmdbuf[0] != '\0') { 3664ff17c8bfSgjelinek /* Run the clone hook */ 3665c75cc341S status = do_subproc(cmdbuf); 3666ff17c8bfSgjelinek if ((status = subproc_status(gettext("brand-specific clone"), 3667ff17c8bfSgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) { 3668ff17c8bfSgjelinek if (status == ZONE_SUBPROC_USAGE && !brand_help) 3669ff17c8bfSgjelinek sub_usage(SHELP_CLONE, CMD_CLONE); 3670ff17c8bfSgjelinek err = Z_ERR; 3671ff17c8bfSgjelinek goto done; 3672ff17c8bfSgjelinek } 3673ff17c8bfSgjelinek 3674ff17c8bfSgjelinek if (brand_help) 3675ff17c8bfSgjelinek return (Z_OK); 3676ff17c8bfSgjelinek 3677ff17c8bfSgjelinek } else { 3678ff17c8bfSgjelinek /* If just help, we're done since there is no brand help. */ 3679ff17c8bfSgjelinek if (brand_help) 3680ff17c8bfSgjelinek return (Z_OK); 3681ff17c8bfSgjelinek 3682ff17c8bfSgjelinek /* Run the built-in clone support. */ 3683ff17c8bfSgjelinek 3684ff17c8bfSgjelinek /* The only explicit built-in method is "copy". */ 3685ff17c8bfSgjelinek if (method != NULL && strcmp(method, "copy") != 0) { 3686ff17c8bfSgjelinek sub_usage(SHELP_CLONE, CMD_CLONE); 3687ff17c8bfSgjelinek err = Z_USAGE; 3688ff17c8bfSgjelinek goto done; 3689ff17c8bfSgjelinek } 3690865e09a4Sgjelinek 36910b5de56dSgjelinek if (snapshot != NULL) { 3692ff17c8bfSgjelinek err = clone_snapshot_zfs(snapshot, zonepath, 3693ff17c8bfSgjelinek validsnapbuf); 36940b5de56dSgjelinek } else { 36950b5de56dSgjelinek /* 3696ff17c8bfSgjelinek * We always copy the clone unless the source is ZFS 3697ff17c8bfSgjelinek * and a ZFS clone worked. We fallback to copying if 3698ff17c8bfSgjelinek * the ZFS clone fails for some reason. 36990b5de56dSgjelinek */ 37000b5de56dSgjelinek err = Z_ERR; 37010b5de56dSgjelinek if (method == NULL && is_zonepath_zfs(source_zonepath)) 3702ff17c8bfSgjelinek err = clone_zfs(source_zonepath, zonepath, 3703ff17c8bfSgjelinek presnapbuf, postsnapbuf); 3704865e09a4Sgjelinek 37055cd08338Sgjelinek if (err != Z_OK) 37060b5de56dSgjelinek err = clone_copy(source_zonepath, zonepath); 37070b5de56dSgjelinek } 3708ff17c8bfSgjelinek } 3709865e09a4Sgjelinek 3710ff17c8bfSgjelinek if (err == Z_OK && postcmdbuf[0] != '\0') { 3711ff17c8bfSgjelinek status = do_subproc(postcmdbuf); 3712ff17c8bfSgjelinek if ((err = subproc_status("postclone", status, B_FALSE)) 3713ff17c8bfSgjelinek != ZONE_SUBPROC_OK) { 3714ff17c8bfSgjelinek zerror(gettext("post-clone configuration failed.")); 3715ff17c8bfSgjelinek err = Z_ERR; 3716ff17c8bfSgjelinek } 3717ff17c8bfSgjelinek } 3718865e09a4Sgjelinek 3719865e09a4Sgjelinek done: 37209acbbeafSnn35248 /* 37219acbbeafSnn35248 * If everything went well, we mark the zone as installed. 37229acbbeafSnn35248 */ 37239acbbeafSnn35248 if (err == Z_OK) { 37249acbbeafSnn35248 err = zone_set_state(target_zone, ZONE_STATE_INSTALLED); 37259acbbeafSnn35248 if (err != Z_OK) { 37269acbbeafSnn35248 errno = err; 37279acbbeafSnn35248 zperror2(target_zone, gettext("could not set state")); 37289acbbeafSnn35248 } 37299acbbeafSnn35248 } 3730ff17c8bfSgjelinek if (!brand_help) 3731ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 3732865e09a4Sgjelinek return ((err == Z_OK) ? Z_OK : Z_ERR); 3733865e09a4Sgjelinek } 3734865e09a4Sgjelinek 373507b574eeSgjelinek /* 37360b5de56dSgjelinek * Used when removing a zonepath after uninstalling or cleaning up after 37370b5de56dSgjelinek * the move subcommand. This handles a zonepath that has non-standard 37380b5de56dSgjelinek * contents so that we will only cleanup the stuff we know about and leave 37390b5de56dSgjelinek * any user data alone. 374007b574eeSgjelinek * 37410b5de56dSgjelinek * If the "all" parameter is true then we should remove the whole zonepath 37420b5de56dSgjelinek * even if it has non-standard files/directories in it. This can be used when 37430b5de56dSgjelinek * we need to cleanup after moving the zonepath across file systems. 37440b5de56dSgjelinek * 37450b5de56dSgjelinek * We "exec" the RMCOMMAND so that the returned status is that of RMCOMMAND 37460b5de56dSgjelinek * and not the shell. 374707b574eeSgjelinek */ 374807b574eeSgjelinek static int 37490b5de56dSgjelinek cleanup_zonepath(char *zonepath, boolean_t all) 375007b574eeSgjelinek { 375107b574eeSgjelinek int status; 37520b5de56dSgjelinek int i; 37530b5de56dSgjelinek boolean_t non_std = B_FALSE; 37540b5de56dSgjelinek struct dirent *dp; 37550b5de56dSgjelinek DIR *dirp; 3756d9e728a2Sgjelinek /* 3757d9e728a2Sgjelinek * The SUNWattached.xml file is expected since it might 3758d9e728a2Sgjelinek * exist if the zone was force-attached after a 3759d9e728a2Sgjelinek * migration. 3760d9e728a2Sgjelinek */ 3761d9e728a2Sgjelinek char *std_entries[] = {"dev", "lu", "root", 3762d9e728a2Sgjelinek "SUNWattached.xml", NULL}; 37630b5de56dSgjelinek /* (MAXPATHLEN * 3) is for the 3 std_entries dirs */ 37640b5de56dSgjelinek char cmdbuf[sizeof (RMCOMMAND) + (MAXPATHLEN * 3) + 64]; 376507b574eeSgjelinek 376607b574eeSgjelinek /* 37670b5de56dSgjelinek * We shouldn't need these checks but lets be paranoid since we 37680b5de56dSgjelinek * could blow away the whole system here if we got the wrong zonepath. 376907b574eeSgjelinek */ 37700b5de56dSgjelinek if (*zonepath == NULL || strcmp(zonepath, "/") == 0) { 37710b5de56dSgjelinek (void) fprintf(stderr, "invalid zonepath '%s'\n", zonepath); 37720b5de56dSgjelinek return (Z_INVAL); 37730b5de56dSgjelinek } 37740b5de56dSgjelinek 377507b574eeSgjelinek /* 37760b5de56dSgjelinek * If the dirpath is already gone (maybe it was manually removed) then 37770b5de56dSgjelinek * we just return Z_OK so that the cleanup is successful. 377807b574eeSgjelinek */ 37790b5de56dSgjelinek if ((dirp = opendir(zonepath)) == NULL) 37800b5de56dSgjelinek return (Z_OK); 37810b5de56dSgjelinek 37820b5de56dSgjelinek /* 37830b5de56dSgjelinek * Look through the zonepath directory to see if there are any 37840b5de56dSgjelinek * non-standard files/dirs. Also skip .zfs since that might be 37850b5de56dSgjelinek * there but we'll handle ZFS file systems as a special case. 37860b5de56dSgjelinek */ 37870b5de56dSgjelinek while ((dp = readdir(dirp)) != NULL) { 37880b5de56dSgjelinek if (strcmp(dp->d_name, ".") == 0 || 37890b5de56dSgjelinek strcmp(dp->d_name, "..") == 0 || 37900b5de56dSgjelinek strcmp(dp->d_name, ".zfs") == 0) 37910b5de56dSgjelinek continue; 37920b5de56dSgjelinek 37930b5de56dSgjelinek for (i = 0; std_entries[i] != NULL; i++) 37940b5de56dSgjelinek if (strcmp(dp->d_name, std_entries[i]) == 0) 37950b5de56dSgjelinek break; 37960b5de56dSgjelinek 37970b5de56dSgjelinek if (std_entries[i] == NULL) 37980b5de56dSgjelinek non_std = B_TRUE; 37990b5de56dSgjelinek } 38000b5de56dSgjelinek (void) closedir(dirp); 38010b5de56dSgjelinek 38020b5de56dSgjelinek if (!all && non_std) { 38030b5de56dSgjelinek /* 38040b5de56dSgjelinek * There are extra, non-standard directories/files in the 38050b5de56dSgjelinek * zonepath so we don't want to remove the zonepath. We 38060b5de56dSgjelinek * just want to remove the standard directories and leave 38070b5de56dSgjelinek * the user data alone. 38080b5de56dSgjelinek */ 38090b5de56dSgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND); 38100b5de56dSgjelinek 38110b5de56dSgjelinek for (i = 0; std_entries[i] != NULL; i++) { 38120b5de56dSgjelinek char tmpbuf[MAXPATHLEN]; 38130b5de56dSgjelinek 38140b5de56dSgjelinek if (snprintf(tmpbuf, sizeof (tmpbuf), " %s/%s", 38150b5de56dSgjelinek zonepath, std_entries[i]) >= sizeof (tmpbuf) || 38160b5de56dSgjelinek strlcat(cmdbuf, tmpbuf, sizeof (cmdbuf)) >= 38170b5de56dSgjelinek sizeof (cmdbuf)) { 38180b5de56dSgjelinek (void) fprintf(stderr, 38190b5de56dSgjelinek gettext("path is too long\n")); 38200b5de56dSgjelinek return (Z_INVAL); 38210b5de56dSgjelinek } 382207b574eeSgjelinek } 382307b574eeSgjelinek 382407b574eeSgjelinek status = do_subproc(cmdbuf); 382507b574eeSgjelinek 38260b5de56dSgjelinek (void) fprintf(stderr, gettext("WARNING: Unable to completely " 38270b5de56dSgjelinek "remove %s\nbecause it contains additional user data. " 38280b5de56dSgjelinek "Only the standard directory\nentries have been " 38290b5de56dSgjelinek "removed.\n"), 38300b5de56dSgjelinek zonepath); 383107b574eeSgjelinek 38329acbbeafSnn35248 return ((subproc_status(RMCOMMAND, status, B_TRUE) == 38339acbbeafSnn35248 ZONE_SUBPROC_OK) ? Z_OK : Z_ERR); 38340b5de56dSgjelinek } 38350b5de56dSgjelinek 38360b5de56dSgjelinek /* 38370b5de56dSgjelinek * There is nothing unexpected in the zonepath, try to get rid of the 38380b5de56dSgjelinek * whole zonepath directory. 38390b5de56dSgjelinek * 38400b5de56dSgjelinek * If the zonepath is its own zfs file system, try to destroy the 38410b5de56dSgjelinek * file system. If that fails for some reason (e.g. it has clones) 38420b5de56dSgjelinek * then we'll just remove the contents of the zonepath. 38430b5de56dSgjelinek */ 38440b5de56dSgjelinek if (is_zonepath_zfs(zonepath)) { 38450b5de56dSgjelinek if (destroy_zfs(zonepath) == Z_OK) 38460b5de56dSgjelinek return (Z_OK); 38470b5de56dSgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND 38480b5de56dSgjelinek " %s/*", zonepath); 38490b5de56dSgjelinek status = do_subproc(cmdbuf); 38509acbbeafSnn35248 return ((subproc_status(RMCOMMAND, status, B_TRUE) == 38519acbbeafSnn35248 ZONE_SUBPROC_OK) ? Z_OK : Z_ERR); 38520b5de56dSgjelinek } 38530b5de56dSgjelinek 38540b5de56dSgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s", 38550b5de56dSgjelinek zonepath); 38560b5de56dSgjelinek status = do_subproc(cmdbuf); 38579acbbeafSnn35248 38589acbbeafSnn35248 return ((subproc_status(RMCOMMAND, status, B_TRUE) == ZONE_SUBPROC_OK) 38599acbbeafSnn35248 ? Z_OK : Z_ERR); 386007b574eeSgjelinek } 386107b574eeSgjelinek 3862865e09a4Sgjelinek static int 3863865e09a4Sgjelinek move_func(int argc, char *argv[]) 3864865e09a4Sgjelinek { 3865865e09a4Sgjelinek char *new_zonepath = NULL; 3866865e09a4Sgjelinek int lockfd; 3867865e09a4Sgjelinek int err, arg; 3868865e09a4Sgjelinek char zonepath[MAXPATHLEN]; 3869865e09a4Sgjelinek zone_dochandle_t handle; 3870865e09a4Sgjelinek boolean_t fast; 38710b5de56dSgjelinek boolean_t is_zfs = B_FALSE; 38720094b373Sjv227347 boolean_t root_fs_mounted = B_FALSE; 38730b5de56dSgjelinek struct dirent *dp; 38740b5de56dSgjelinek DIR *dirp; 38750b5de56dSgjelinek boolean_t empty = B_TRUE; 3876865e09a4Sgjelinek boolean_t revert; 3877865e09a4Sgjelinek struct stat zonepath_buf; 3878865e09a4Sgjelinek struct stat new_zonepath_buf; 38790094b373Sjv227347 zone_mounts_t mounts; 3880865e09a4Sgjelinek 3881865e09a4Sgjelinek if (zonecfg_in_alt_root()) { 3882865e09a4Sgjelinek zerror(gettext("cannot move zone in alternate root")); 3883865e09a4Sgjelinek return (Z_ERR); 3884865e09a4Sgjelinek } 3885865e09a4Sgjelinek 3886865e09a4Sgjelinek optind = 0; 3887865e09a4Sgjelinek if ((arg = getopt(argc, argv, "?")) != EOF) { 3888865e09a4Sgjelinek switch (arg) { 3889865e09a4Sgjelinek case '?': 3890865e09a4Sgjelinek sub_usage(SHELP_MOVE, CMD_MOVE); 3891865e09a4Sgjelinek return (optopt == '?' ? Z_OK : Z_USAGE); 3892865e09a4Sgjelinek default: 3893865e09a4Sgjelinek sub_usage(SHELP_MOVE, CMD_MOVE); 3894865e09a4Sgjelinek return (Z_USAGE); 3895865e09a4Sgjelinek } 3896865e09a4Sgjelinek } 3897865e09a4Sgjelinek if (argc != (optind + 1)) { 3898865e09a4Sgjelinek sub_usage(SHELP_MOVE, CMD_MOVE); 3899865e09a4Sgjelinek return (Z_USAGE); 3900865e09a4Sgjelinek } 3901865e09a4Sgjelinek new_zonepath = argv[optind]; 39029acbbeafSnn35248 if (sanity_check(target_zone, CMD_MOVE, B_FALSE, B_TRUE, B_FALSE) 39039acbbeafSnn35248 != Z_OK) 3904865e09a4Sgjelinek return (Z_ERR); 3905ce28b40eSzt129084 if (verify_details(CMD_MOVE, argv) != Z_OK) 3906865e09a4Sgjelinek return (Z_ERR); 3907865e09a4Sgjelinek 3908865e09a4Sgjelinek /* 3909865e09a4Sgjelinek * Check out the new zonepath. This has the side effect of creating 3910865e09a4Sgjelinek * a directory for the new zonepath. We depend on this later when we 39110b5de56dSgjelinek * stat to see if we are doing a cross file system move or not. 3912865e09a4Sgjelinek */ 3913865e09a4Sgjelinek if (validate_zonepath(new_zonepath, CMD_MOVE) != Z_OK) 3914865e09a4Sgjelinek return (Z_ERR); 3915865e09a4Sgjelinek 3916865e09a4Sgjelinek if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath))) 3917865e09a4Sgjelinek != Z_OK) { 3918865e09a4Sgjelinek errno = err; 3919865e09a4Sgjelinek zperror2(target_zone, gettext("could not get zone path")); 3920865e09a4Sgjelinek return (Z_ERR); 3921865e09a4Sgjelinek } 3922865e09a4Sgjelinek 3923865e09a4Sgjelinek if (stat(zonepath, &zonepath_buf) == -1) { 3924865e09a4Sgjelinek zperror(gettext("could not stat zone path"), B_FALSE); 3925865e09a4Sgjelinek return (Z_ERR); 3926865e09a4Sgjelinek } 3927865e09a4Sgjelinek 3928865e09a4Sgjelinek if (stat(new_zonepath, &new_zonepath_buf) == -1) { 3929865e09a4Sgjelinek zperror(gettext("could not stat new zone path"), B_FALSE); 3930865e09a4Sgjelinek return (Z_ERR); 3931865e09a4Sgjelinek } 3932865e09a4Sgjelinek 39330b5de56dSgjelinek /* 39340b5de56dSgjelinek * Check if the destination directory is empty. 39350b5de56dSgjelinek */ 39360b5de56dSgjelinek if ((dirp = opendir(new_zonepath)) == NULL) { 39370b5de56dSgjelinek zperror(gettext("could not open new zone path"), B_FALSE); 39380b5de56dSgjelinek return (Z_ERR); 39390b5de56dSgjelinek } 39400b5de56dSgjelinek while ((dp = readdir(dirp)) != (struct dirent *)0) { 39410b5de56dSgjelinek if (strcmp(dp->d_name, ".") == 0 || 39420b5de56dSgjelinek strcmp(dp->d_name, "..") == 0) 39430b5de56dSgjelinek continue; 39440b5de56dSgjelinek empty = B_FALSE; 39450b5de56dSgjelinek break; 39460b5de56dSgjelinek } 39470b5de56dSgjelinek (void) closedir(dirp); 39480b5de56dSgjelinek 39490b5de56dSgjelinek /* Error if there is anything in the destination directory. */ 39500b5de56dSgjelinek if (!empty) { 39510b5de56dSgjelinek (void) fprintf(stderr, gettext("could not move zone to %s: " 39520b5de56dSgjelinek "directory not empty\n"), new_zonepath); 39530b5de56dSgjelinek return (Z_ERR); 39540b5de56dSgjelinek } 39550b5de56dSgjelinek 39560094b373Sjv227347 /* 39570094b373Sjv227347 * Collect information about mounts within the zone's zonepath. 39580094b373Sjv227347 * Overlay mounts on the zone's root directory are erroneous. 39590094b373Sjv227347 * Bail if we encounter any unexpected mounts. 39600094b373Sjv227347 */ 39610094b373Sjv227347 if (zone_mounts_init(&mounts, zonepath) != 0) 3962865e09a4Sgjelinek return (Z_ERR); 39630094b373Sjv227347 if (mounts.num_root_overlay_mounts != 0) { 39640094b373Sjv227347 zerror(gettext("%d overlay mount(s) detected on %s/root."), 39650094b373Sjv227347 mounts.num_root_overlay_mounts, zonepath); 39660094b373Sjv227347 goto err_and_mounts_destroy; 3967865e09a4Sgjelinek } 39680094b373Sjv227347 if (mounts.num_unexpected_mounts != 0) 39690094b373Sjv227347 goto err_and_mounts_destroy; 3970865e09a4Sgjelinek 3971865e09a4Sgjelinek /* 3972865e09a4Sgjelinek * Check if we are moving in the same file system and can do a fast 3973865e09a4Sgjelinek * move or if we are crossing file systems and have to copy the data. 3974865e09a4Sgjelinek */ 3975865e09a4Sgjelinek fast = (zonepath_buf.st_dev == new_zonepath_buf.st_dev); 3976865e09a4Sgjelinek 3977865e09a4Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 3978865e09a4Sgjelinek zperror(cmd_to_str(CMD_MOVE), B_TRUE); 39790094b373Sjv227347 goto err_and_mounts_destroy; 3980865e09a4Sgjelinek } 3981865e09a4Sgjelinek 3982865e09a4Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 3983865e09a4Sgjelinek errno = err; 3984865e09a4Sgjelinek zperror(cmd_to_str(CMD_MOVE), B_TRUE); 39850094b373Sjv227347 goto err_and_fini_handle; 3986865e09a4Sgjelinek } 3987865e09a4Sgjelinek 3988ff17c8bfSgjelinek if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) { 3989865e09a4Sgjelinek zerror(gettext("another %s may have an operation in progress."), 3990865e09a4Sgjelinek "zoneadm"); 39910094b373Sjv227347 goto err_and_fini_handle; 3992865e09a4Sgjelinek } 3993865e09a4Sgjelinek 3994865e09a4Sgjelinek /* 39950094b373Sjv227347 * Unmount the zone's root filesystem before we move the zone's 39960094b373Sjv227347 * zonepath. 39970094b373Sjv227347 */ 39980094b373Sjv227347 if (zone_unmount_rootfs(&mounts, zonepath, B_FALSE) != 0) 39990094b373Sjv227347 goto err_and_rele_lockfile; 40000094b373Sjv227347 40010094b373Sjv227347 /* 40020b5de56dSgjelinek * We're making some file system changes now so we have to clean up 40030b5de56dSgjelinek * the file system before we are done. This will either clean up the 4004865e09a4Sgjelinek * new zonepath if the zonecfg update failed or it will clean up the 4005865e09a4Sgjelinek * old zonepath if everything is ok. 4006865e09a4Sgjelinek */ 4007865e09a4Sgjelinek revert = B_TRUE; 4008865e09a4Sgjelinek 40090b5de56dSgjelinek if (is_zonepath_zfs(zonepath) && 40100b5de56dSgjelinek move_zfs(zonepath, new_zonepath) != Z_ERR) { 40110b5de56dSgjelinek is_zfs = B_TRUE; 40120b5de56dSgjelinek 40130b5de56dSgjelinek } else if (fast) { 4014865e09a4Sgjelinek /* same file system, use rename for a quick move */ 4015865e09a4Sgjelinek 4016865e09a4Sgjelinek /* 4017865e09a4Sgjelinek * Remove the new_zonepath directory that got created above 4018865e09a4Sgjelinek * during the validation. It gets in the way of the rename. 4019865e09a4Sgjelinek */ 4020865e09a4Sgjelinek if (rmdir(new_zonepath) != 0) { 4021865e09a4Sgjelinek zperror(gettext("could not rmdir new zone path"), 4022865e09a4Sgjelinek B_FALSE); 40230094b373Sjv227347 (void) zone_mount_rootfs(&mounts, zonepath); 40240094b373Sjv227347 goto err_and_rele_lockfile; 4025865e09a4Sgjelinek } 4026865e09a4Sgjelinek 4027865e09a4Sgjelinek if (rename(zonepath, new_zonepath) != 0) { 4028865e09a4Sgjelinek /* 4029865e09a4Sgjelinek * If this fails we don't need to do all of the 4030865e09a4Sgjelinek * cleanup that happens for the rest of the code 4031865e09a4Sgjelinek * so just return from this error. 4032865e09a4Sgjelinek */ 4033865e09a4Sgjelinek zperror(gettext("could not move zone"), B_FALSE); 40340094b373Sjv227347 (void) zone_mount_rootfs(&mounts, zonepath); 40350094b373Sjv227347 goto err_and_rele_lockfile; 4036865e09a4Sgjelinek } 4037865e09a4Sgjelinek 4038865e09a4Sgjelinek } else { 40390b5de56dSgjelinek /* 40400b5de56dSgjelinek * Attempt to create a ZFS fs for the new zonepath. As usual, 40410b5de56dSgjelinek * we don't care if this works or not since we always have the 40420b5de56dSgjelinek * default behavior of a simple directory for the zonepath. 40430b5de56dSgjelinek */ 40440b5de56dSgjelinek create_zfs_zonepath(new_zonepath); 40450b5de56dSgjelinek 4046865e09a4Sgjelinek (void) printf(gettext( 40470b5de56dSgjelinek "Moving across file systems; copying zonepath %s..."), 4048865e09a4Sgjelinek zonepath); 4049865e09a4Sgjelinek (void) fflush(stdout); 4050865e09a4Sgjelinek 4051865e09a4Sgjelinek err = copy_zone(zonepath, new_zonepath); 4052865e09a4Sgjelinek 4053865e09a4Sgjelinek (void) printf("\n"); 4054865e09a4Sgjelinek if (err != Z_OK) 4055865e09a4Sgjelinek goto done; 4056865e09a4Sgjelinek } 4057865e09a4Sgjelinek 40580094b373Sjv227347 /* 40590094b373Sjv227347 * Mount the zone's root filesystem in the new zonepath if there was 40600094b373Sjv227347 * a root mount prior to the move. 40610094b373Sjv227347 */ 40620094b373Sjv227347 if (zone_mount_rootfs(&mounts, new_zonepath) != 0) { 40630094b373Sjv227347 err = Z_ERR; 40640094b373Sjv227347 goto done; 40650094b373Sjv227347 } 40660094b373Sjv227347 root_fs_mounted = B_TRUE; 40670094b373Sjv227347 4068865e09a4Sgjelinek if ((err = zonecfg_set_zonepath(handle, new_zonepath)) != Z_OK) { 4069865e09a4Sgjelinek errno = err; 4070865e09a4Sgjelinek zperror(gettext("could not set new zonepath"), B_TRUE); 4071865e09a4Sgjelinek goto done; 4072865e09a4Sgjelinek } 4073865e09a4Sgjelinek 4074865e09a4Sgjelinek if ((err = zonecfg_save(handle)) != Z_OK) { 4075865e09a4Sgjelinek errno = err; 4076865e09a4Sgjelinek zperror(gettext("zonecfg save failed"), B_TRUE); 4077865e09a4Sgjelinek goto done; 4078865e09a4Sgjelinek } 4079865e09a4Sgjelinek 4080865e09a4Sgjelinek revert = B_FALSE; 4081865e09a4Sgjelinek 4082865e09a4Sgjelinek done: 4083865e09a4Sgjelinek zonecfg_fini_handle(handle); 4084ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 4085865e09a4Sgjelinek 4086865e09a4Sgjelinek /* 40870b5de56dSgjelinek * Clean up the file system based on how things went. We either 4088865e09a4Sgjelinek * clean up the new zonepath if the operation failed for some reason 4089865e09a4Sgjelinek * or we clean up the old zonepath if everything is ok. 4090865e09a4Sgjelinek */ 4091865e09a4Sgjelinek if (revert) { 40920094b373Sjv227347 /* 40930094b373Sjv227347 * Check for the unlikely scenario in which the zone's 40940094b373Sjv227347 * zonepath and its root file system moved but libzonecfg 40950094b373Sjv227347 * couldn't save the new zonepath to the zone's configuration 40960094b373Sjv227347 * file. The mounted root filesystem must be unmounted before 40970094b373Sjv227347 * zoneadm restores the zone's zonepath. 40980094b373Sjv227347 */ 40990094b373Sjv227347 if (root_fs_mounted && zone_unmount_rootfs(&mounts, 41000094b373Sjv227347 new_zonepath, B_TRUE) != 0) { 41010094b373Sjv227347 /* 41020094b373Sjv227347 * We can't forcibly unmount the zone's root file system 41030094b373Sjv227347 * from the new zonepath. Bail! 41040094b373Sjv227347 */ 41050094b373Sjv227347 zerror(gettext("fatal error: cannot unmount %s/root\n"), 41060094b373Sjv227347 new_zonepath); 41070094b373Sjv227347 goto err_and_mounts_destroy; 41080094b373Sjv227347 } 41090094b373Sjv227347 4110865e09a4Sgjelinek /* The zonecfg update failed, cleanup the new zonepath. */ 41110b5de56dSgjelinek if (is_zfs) { 41120b5de56dSgjelinek if (move_zfs(new_zonepath, zonepath) == Z_ERR) { 41130b5de56dSgjelinek (void) fprintf(stderr, gettext("could not " 41140b5de56dSgjelinek "restore zonepath, the zfs mountpoint is " 41150b5de56dSgjelinek "set as:\n%s\n"), new_zonepath); 41160b5de56dSgjelinek /* 41170b5de56dSgjelinek * err is already != Z_OK since we're reverting 41180b5de56dSgjelinek */ 41190094b373Sjv227347 } else { 41200094b373Sjv227347 (void) zone_mount_rootfs(&mounts, zonepath); 41210b5de56dSgjelinek } 41220b5de56dSgjelinek } else if (fast) { 4123865e09a4Sgjelinek if (rename(new_zonepath, zonepath) != 0) { 4124865e09a4Sgjelinek zperror(gettext("could not restore zonepath"), 4125865e09a4Sgjelinek B_FALSE); 4126865e09a4Sgjelinek /* 4127865e09a4Sgjelinek * err is already != Z_OK since we're reverting 4128865e09a4Sgjelinek */ 41290094b373Sjv227347 } else { 41300094b373Sjv227347 (void) zone_mount_rootfs(&mounts, zonepath); 4131865e09a4Sgjelinek } 4132865e09a4Sgjelinek } else { 4133865e09a4Sgjelinek (void) printf(gettext("Cleaning up zonepath %s..."), 4134865e09a4Sgjelinek new_zonepath); 4135865e09a4Sgjelinek (void) fflush(stdout); 41360b5de56dSgjelinek err = cleanup_zonepath(new_zonepath, B_TRUE); 4137865e09a4Sgjelinek (void) printf("\n"); 4138865e09a4Sgjelinek 413907b574eeSgjelinek if (err != Z_OK) { 4140865e09a4Sgjelinek errno = err; 4141865e09a4Sgjelinek zperror(gettext("could not remove new " 4142865e09a4Sgjelinek "zonepath"), B_TRUE); 4143865e09a4Sgjelinek } else { 4144865e09a4Sgjelinek /* 4145865e09a4Sgjelinek * Because we're reverting we know the mainline 4146865e09a4Sgjelinek * code failed but we just reused the err 4147865e09a4Sgjelinek * variable so we reset it back to Z_ERR. 4148865e09a4Sgjelinek */ 4149865e09a4Sgjelinek err = Z_ERR; 4150865e09a4Sgjelinek } 4151865e09a4Sgjelinek 41520094b373Sjv227347 (void) zone_mount_rootfs(&mounts, zonepath); 41530094b373Sjv227347 } 4154865e09a4Sgjelinek } else { 4155865e09a4Sgjelinek /* The move was successful, cleanup the old zonepath. */ 41560b5de56dSgjelinek if (!is_zfs && !fast) { 4157865e09a4Sgjelinek (void) printf( 4158865e09a4Sgjelinek gettext("Cleaning up zonepath %s..."), zonepath); 4159865e09a4Sgjelinek (void) fflush(stdout); 41600b5de56dSgjelinek err = cleanup_zonepath(zonepath, B_TRUE); 4161865e09a4Sgjelinek (void) printf("\n"); 4162865e09a4Sgjelinek 416307b574eeSgjelinek if (err != Z_OK) { 4164865e09a4Sgjelinek errno = err; 4165865e09a4Sgjelinek zperror(gettext("could not remove zonepath"), 4166865e09a4Sgjelinek B_TRUE); 4167865e09a4Sgjelinek } 4168865e09a4Sgjelinek } 4169865e09a4Sgjelinek } 4170865e09a4Sgjelinek 41710094b373Sjv227347 zone_mounts_destroy(&mounts); 4172865e09a4Sgjelinek return ((err == Z_OK) ? Z_OK : Z_ERR); 41730094b373Sjv227347 41740094b373Sjv227347 err_and_rele_lockfile: 41750094b373Sjv227347 zonecfg_release_lock_file(target_zone, lockfd); 41760094b373Sjv227347 err_and_fini_handle: 41770094b373Sjv227347 zonecfg_fini_handle(handle); 41780094b373Sjv227347 err_and_mounts_destroy: 41790094b373Sjv227347 zone_mounts_destroy(&mounts); 41800094b373Sjv227347 return (Z_ERR); 4181865e09a4Sgjelinek } 4182865e09a4Sgjelinek 4183ff17c8bfSgjelinek /* ARGSUSED */ 4184ee519a1fSgjelinek static int 4185ee519a1fSgjelinek detach_func(int argc, char *argv[]) 4186ee519a1fSgjelinek { 418771443f5aS int lockfd = -1; 4188ee519a1fSgjelinek int err, arg; 4189ee519a1fSgjelinek char zonepath[MAXPATHLEN]; 419037774979Sgjelinek char cmdbuf[MAXPATHLEN]; 4191ff17c8bfSgjelinek char precmdbuf[MAXPATHLEN]; 41928cd327d5Sgjelinek boolean_t execute = B_TRUE; 4193ff17c8bfSgjelinek boolean_t brand_help = B_FALSE; 419437774979Sgjelinek brand_handle_t bh = NULL; 4195ff17c8bfSgjelinek int status; 4196ee519a1fSgjelinek 4197ee519a1fSgjelinek if (zonecfg_in_alt_root()) { 4198ee519a1fSgjelinek zerror(gettext("cannot detach zone in alternate root")); 4199ee519a1fSgjelinek return (Z_ERR); 4200ee519a1fSgjelinek } 4201ee519a1fSgjelinek 4202ff17c8bfSgjelinek /* Check the argv string for args we handle internally */ 4203ee519a1fSgjelinek optind = 0; 4204ff17c8bfSgjelinek opterr = 0; 4205ff17c8bfSgjelinek while ((arg = getopt(argc, argv, "?n")) != EOF) { 4206ee519a1fSgjelinek switch (arg) { 4207ee519a1fSgjelinek case '?': 4208ff17c8bfSgjelinek if (optopt == '?') { 4209ee519a1fSgjelinek sub_usage(SHELP_DETACH, CMD_DETACH); 4210ff17c8bfSgjelinek brand_help = B_TRUE; 4211ff17c8bfSgjelinek } 4212ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 4213ff17c8bfSgjelinek break; 42148cd327d5Sgjelinek case 'n': 42158cd327d5Sgjelinek execute = B_FALSE; 42168cd327d5Sgjelinek break; 4217ee519a1fSgjelinek default: 4218ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 4219ff17c8bfSgjelinek break; 4220ee519a1fSgjelinek } 4221ee519a1fSgjelinek } 42229acbbeafSnn35248 4223ff17c8bfSgjelinek if (brand_help) 4224ff17c8bfSgjelinek execute = B_FALSE; 4225ff17c8bfSgjelinek 42268cd327d5Sgjelinek if (execute) { 42279acbbeafSnn35248 if (sanity_check(target_zone, CMD_DETACH, B_FALSE, B_TRUE, 42289acbbeafSnn35248 B_FALSE) != Z_OK) 4229ee519a1fSgjelinek return (Z_ERR); 4230ce28b40eSzt129084 if (verify_details(CMD_DETACH, argv) != Z_OK) 4231ee519a1fSgjelinek return (Z_ERR); 42328cd327d5Sgjelinek } else { 42338cd327d5Sgjelinek /* 42348cd327d5Sgjelinek * We want a dry-run to work for a non-privileged user so we 42358cd327d5Sgjelinek * only do minimal validation. 42368cd327d5Sgjelinek */ 42378cd327d5Sgjelinek if (target_zone == NULL) { 42388cd327d5Sgjelinek zerror(gettext("no zone specified")); 42398cd327d5Sgjelinek return (Z_ERR); 42408cd327d5Sgjelinek } 42418cd327d5Sgjelinek 42428cd327d5Sgjelinek if (strcmp(target_zone, GLOBAL_ZONENAME) == 0) { 42438cd327d5Sgjelinek zerror(gettext("%s operation is invalid for the " 42448cd327d5Sgjelinek "global zone."), cmd_to_str(CMD_DETACH)); 42458cd327d5Sgjelinek return (Z_ERR); 42468cd327d5Sgjelinek } 42478cd327d5Sgjelinek } 4248ee519a1fSgjelinek 4249ee519a1fSgjelinek if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath))) 4250ee519a1fSgjelinek != Z_OK) { 4251ee519a1fSgjelinek errno = err; 4252ee519a1fSgjelinek zperror2(target_zone, gettext("could not get zone path")); 4253ee519a1fSgjelinek return (Z_ERR); 4254ee519a1fSgjelinek } 4255ee519a1fSgjelinek 4256ff17c8bfSgjelinek /* Fetch the detach and predetach hooks from the brand configuration. */ 425737774979Sgjelinek if ((bh = brand_open(target_brand)) == NULL) { 425837774979Sgjelinek zerror(gettext("missing or invalid brand")); 425937774979Sgjelinek return (Z_ERR); 426037774979Sgjelinek } 426137774979Sgjelinek 4262ff17c8bfSgjelinek if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_detach, target_zone, 4263ff17c8bfSgjelinek zonepath) != Z_OK) { 4264ff17c8bfSgjelinek zerror("invalid brand configuration: missing detach resource"); 4265ff17c8bfSgjelinek brand_close(bh); 4266ff17c8bfSgjelinek return (Z_ERR); 4267ff17c8bfSgjelinek } 4268ff17c8bfSgjelinek 4269ff17c8bfSgjelinek if (get_hook(bh, precmdbuf, sizeof (precmdbuf), brand_get_predetach, 4270ff17c8bfSgjelinek target_zone, zonepath) != Z_OK) { 427137774979Sgjelinek zerror("invalid brand configuration: missing predetach " 427237774979Sgjelinek "resource"); 427337774979Sgjelinek brand_close(bh); 427437774979Sgjelinek return (Z_ERR); 427537774979Sgjelinek } 427637774979Sgjelinek brand_close(bh); 427737774979Sgjelinek 4278ff17c8bfSgjelinek /* Append all options to predetach hook. */ 4279ff17c8bfSgjelinek if (addoptions(precmdbuf, argv, sizeof (precmdbuf)) != Z_OK) 428037774979Sgjelinek return (Z_ERR); 428137774979Sgjelinek 4282ff17c8bfSgjelinek /* Append all options to detach hook. */ 4283ff17c8bfSgjelinek if (addoptions(cmdbuf, argv, sizeof (cmdbuf)) != Z_OK) 428437774979Sgjelinek return (Z_ERR); 428537774979Sgjelinek 4286ff17c8bfSgjelinek if (execute && zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) { 4287ee519a1fSgjelinek zerror(gettext("another %s may have an operation in progress."), 4288ee519a1fSgjelinek "zoneadm"); 4289ee519a1fSgjelinek return (Z_ERR); 4290ee519a1fSgjelinek } 4291ee519a1fSgjelinek 4292ff17c8bfSgjelinek /* If we have a brand predetach hook, run it. */ 4293ff17c8bfSgjelinek if (!brand_help && precmdbuf[0] != '\0') { 4294ff17c8bfSgjelinek status = do_subproc(precmdbuf); 4295ff17c8bfSgjelinek if (subproc_status(gettext("brand-specific predetach"), 4296ff17c8bfSgjelinek status, B_FALSE) != ZONE_SUBPROC_OK) { 4297ff17c8bfSgjelinek 429871443f5aS if (execute) { 429971443f5aS assert(lockfd >= 0); 4300ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 430171443f5aS lockfd = -1; 430271443f5aS } 430371443f5aS 430471443f5aS assert(lockfd == -1); 4305ff17c8bfSgjelinek return (Z_ERR); 4306ff17c8bfSgjelinek } 4307ff17c8bfSgjelinek } 4308ff17c8bfSgjelinek 4309ff17c8bfSgjelinek if (cmdbuf[0] != '\0') { 4310ff17c8bfSgjelinek /* Run the detach hook */ 4311c75cc341S status = do_subproc(cmdbuf); 4312ff17c8bfSgjelinek if ((status = subproc_status(gettext("brand-specific detach"), 4313ff17c8bfSgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK) { 4314ff17c8bfSgjelinek if (status == ZONE_SUBPROC_USAGE && !brand_help) 4315ff17c8bfSgjelinek sub_usage(SHELP_DETACH, CMD_DETACH); 4316ff17c8bfSgjelinek 431771443f5aS if (execute) { 431871443f5aS assert(lockfd >= 0); 4319ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 432071443f5aS lockfd = -1; 432171443f5aS } 4322ff17c8bfSgjelinek 432371443f5aS assert(lockfd == -1); 4324ff17c8bfSgjelinek return (Z_ERR); 4325ff17c8bfSgjelinek } 4326ff17c8bfSgjelinek 4327ff17c8bfSgjelinek } else { 432871443f5aS zone_dochandle_t handle; 432971443f5aS 4330ff17c8bfSgjelinek /* If just help, we're done since there is no brand help. */ 433171443f5aS if (brand_help) { 433271443f5aS assert(lockfd == -1); 4333ff17c8bfSgjelinek return (Z_OK); 433471443f5aS } 4335ff17c8bfSgjelinek 4336ff17c8bfSgjelinek /* 4337ff17c8bfSgjelinek * Run the built-in detach support. Just generate a simple 4338ff17c8bfSgjelinek * zone definition XML file and detach. 4339ff17c8bfSgjelinek */ 4340ff17c8bfSgjelinek 4341ff17c8bfSgjelinek /* Don't detach the zone if anything is still mounted there */ 4342ff17c8bfSgjelinek if (execute && zonecfg_find_mounts(zonepath, NULL, NULL)) { 4343ff17c8bfSgjelinek (void) fprintf(stderr, gettext("These file systems are " 4344ff17c8bfSgjelinek "mounted on subdirectories of %s.\n"), zonepath); 4345ff17c8bfSgjelinek (void) zonecfg_find_mounts(zonepath, zfm_print, NULL); 4346ff17c8bfSgjelinek err = ZONE_SUBPROC_NOTCOMPLETE; 4347ff17c8bfSgjelinek goto done; 4348ff17c8bfSgjelinek } 4349ff17c8bfSgjelinek 4350ff17c8bfSgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 4351ff17c8bfSgjelinek zperror(cmd_to_str(CMD_DETACH), B_TRUE); 4352ff17c8bfSgjelinek err = ZONE_SUBPROC_NOTCOMPLETE; 4353ff17c8bfSgjelinek goto done; 4354ff17c8bfSgjelinek } 4355ff17c8bfSgjelinek 4356ff17c8bfSgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 4357ee519a1fSgjelinek errno = err; 4358ff17c8bfSgjelinek zperror(cmd_to_str(CMD_DETACH), B_TRUE); 4359ff17c8bfSgjelinek 436071443f5aS } else if ((err = zonecfg_detach_save(handle, 4361ff17c8bfSgjelinek (execute ? 0 : ZONE_DRY_RUN))) != Z_OK) { 4362ff17c8bfSgjelinek errno = err; 4363ff17c8bfSgjelinek zperror(gettext("saving the detach manifest failed"), 4364ee519a1fSgjelinek B_TRUE); 4365ee519a1fSgjelinek } 4366ee519a1fSgjelinek 4367ff17c8bfSgjelinek zonecfg_fini_handle(handle); 436871443f5aS if (err != Z_OK) 436971443f5aS goto done; 4370ee519a1fSgjelinek } 4371ee519a1fSgjelinek 43728cd327d5Sgjelinek /* 43738cd327d5Sgjelinek * Set the zone state back to configured unless we are running with the 43748cd327d5Sgjelinek * no-execute option. 43758cd327d5Sgjelinek */ 43768cd327d5Sgjelinek if (execute && (err = zone_set_state(target_zone, 43778cd327d5Sgjelinek ZONE_STATE_CONFIGURED)) != Z_OK) { 4378ee519a1fSgjelinek errno = err; 4379ee519a1fSgjelinek zperror(gettext("could not reset state"), B_TRUE); 4380ee519a1fSgjelinek } 4381ee519a1fSgjelinek 4382ee519a1fSgjelinek done: 438371443f5aS if (execute) { 438471443f5aS assert(lockfd >= 0); 4385ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 438671443f5aS lockfd = -1; 438771443f5aS } 4388ee519a1fSgjelinek 438971443f5aS assert(lockfd == -1); 4390ee519a1fSgjelinek return ((err == Z_OK) ? Z_OK : Z_ERR); 4391ee519a1fSgjelinek } 4392ee519a1fSgjelinek 4393ee519a1fSgjelinek /* 4394ff17c8bfSgjelinek * Determine the brand when doing a dry-run attach. The zone does not have to 4395ff17c8bfSgjelinek * exist, so we have to read the incoming manifest to determine the zone's 4396ff17c8bfSgjelinek * brand. 4397ff17c8bfSgjelinek * 4398ff17c8bfSgjelinek * Because the manifest has to be processed twice; once to determine the brand 4399ff17c8bfSgjelinek * and once to do the brand-specific attach logic, we always read it into a tmp 4400ff17c8bfSgjelinek * file. This handles the manifest coming from stdin or a regular file. The 4401ff17c8bfSgjelinek * tmpname parameter returns the name of the temporary file that the manifest 4402ff17c8bfSgjelinek * was read into. 4403ee519a1fSgjelinek */ 4404ee519a1fSgjelinek static int 4405ff17c8bfSgjelinek dryrun_get_brand(char *manifest_path, char *tmpname, int size) 44068cd327d5Sgjelinek { 44078cd327d5Sgjelinek int fd; 44088cd327d5Sgjelinek int err; 4409ff17c8bfSgjelinek int res = Z_OK; 44108cd327d5Sgjelinek zone_dochandle_t local_handle; 44118cd327d5Sgjelinek zone_dochandle_t rem_handle = NULL; 4412ff17c8bfSgjelinek int len; 4413ff17c8bfSgjelinek int ofd; 4414ff17c8bfSgjelinek char buf[512]; 44158cd327d5Sgjelinek 44168cd327d5Sgjelinek if (strcmp(manifest_path, "-") == 0) { 4417ff17c8bfSgjelinek fd = STDIN_FILENO; 4418ff17c8bfSgjelinek } else { 4419ff17c8bfSgjelinek if ((fd = open(manifest_path, O_RDONLY)) < 0) { 4420ff17c8bfSgjelinek if (getcwd(buf, sizeof (buf)) == NULL) 4421ff17c8bfSgjelinek (void) strlcpy(buf, "/", sizeof (buf)); 4422ff17c8bfSgjelinek zerror(gettext("could not open manifest path %s%s: %s"), 4423ff17c8bfSgjelinek (*manifest_path == '/' ? "" : buf), manifest_path, 4424ff17c8bfSgjelinek strerror(errno)); 4425ff17c8bfSgjelinek return (Z_ERR); 4426ff17c8bfSgjelinek } 4427ff17c8bfSgjelinek } 4428ff17c8bfSgjelinek 4429ff17c8bfSgjelinek (void) snprintf(tmpname, size, "/var/run/zone.%d", getpid()); 4430ff17c8bfSgjelinek 4431ff17c8bfSgjelinek if ((ofd = open(tmpname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { 4432ff17c8bfSgjelinek zperror(gettext("could not save manifest"), B_FALSE); 4433ff17c8bfSgjelinek (void) close(fd); 4434ff17c8bfSgjelinek return (Z_ERR); 4435ff17c8bfSgjelinek } 4436ff17c8bfSgjelinek 4437ff17c8bfSgjelinek while ((len = read(fd, buf, sizeof (buf))) > 0) { 4438ff17c8bfSgjelinek if (write(ofd, buf, len) == -1) { 4439ff17c8bfSgjelinek zperror(gettext("could not save manifest"), B_FALSE); 4440ff17c8bfSgjelinek (void) close(ofd); 4441ff17c8bfSgjelinek (void) close(fd); 4442ff17c8bfSgjelinek return (Z_ERR); 4443ff17c8bfSgjelinek } 4444ff17c8bfSgjelinek } 4445ff17c8bfSgjelinek 4446ff17c8bfSgjelinek if (close(ofd) != 0) { 4447ff17c8bfSgjelinek zperror(gettext("could not save manifest"), B_FALSE); 4448ff17c8bfSgjelinek (void) close(fd); 4449ff17c8bfSgjelinek return (Z_ERR); 4450ff17c8bfSgjelinek } 4451ff17c8bfSgjelinek 4452ff17c8bfSgjelinek (void) close(fd); 4453ff17c8bfSgjelinek 4454ff17c8bfSgjelinek if ((fd = open(tmpname, O_RDONLY)) < 0) { 44558cd327d5Sgjelinek zperror(gettext("could not open manifest path"), B_FALSE); 44568cd327d5Sgjelinek return (Z_ERR); 44578cd327d5Sgjelinek } 44588cd327d5Sgjelinek 44598cd327d5Sgjelinek if ((local_handle = zonecfg_init_handle()) == NULL) { 44608cd327d5Sgjelinek zperror(cmd_to_str(CMD_ATTACH), B_TRUE); 44618cd327d5Sgjelinek res = Z_ERR; 44628cd327d5Sgjelinek goto done; 44638cd327d5Sgjelinek } 44648cd327d5Sgjelinek 44658cd327d5Sgjelinek if ((rem_handle = zonecfg_init_handle()) == NULL) { 44668cd327d5Sgjelinek zperror(cmd_to_str(CMD_ATTACH), B_TRUE); 44678cd327d5Sgjelinek res = Z_ERR; 44688cd327d5Sgjelinek goto done; 44698cd327d5Sgjelinek } 44708cd327d5Sgjelinek 44718cd327d5Sgjelinek if ((err = zonecfg_attach_manifest(fd, local_handle, rem_handle)) 44728cd327d5Sgjelinek != Z_OK) { 44738cd327d5Sgjelinek res = Z_ERR; 4474d9e728a2Sgjelinek 4475d9e728a2Sgjelinek if (err == Z_INVALID_DOCUMENT) { 4476d9e728a2Sgjelinek struct stat st; 4477d9e728a2Sgjelinek char buf[6]; 4478d9e728a2Sgjelinek 4479d9e728a2Sgjelinek if (strcmp(manifest_path, "-") == 0) { 4480d9e728a2Sgjelinek zerror(gettext("Input is not a valid XML " 4481d9e728a2Sgjelinek "file")); 4482d9e728a2Sgjelinek goto done; 4483d9e728a2Sgjelinek } 4484d9e728a2Sgjelinek 4485d9e728a2Sgjelinek if (fstat(fd, &st) == -1 || !S_ISREG(st.st_mode)) { 4486d9e728a2Sgjelinek zerror(gettext("%s is not an XML file"), 4487d9e728a2Sgjelinek manifest_path); 4488d9e728a2Sgjelinek goto done; 4489d9e728a2Sgjelinek } 4490d9e728a2Sgjelinek 4491d9e728a2Sgjelinek bzero(buf, sizeof (buf)); 4492d9e728a2Sgjelinek (void) lseek(fd, 0L, SEEK_SET); 4493d9e728a2Sgjelinek if (read(fd, buf, sizeof (buf) - 1) < 0 || 4494d9e728a2Sgjelinek strncmp(buf, "<?xml", 5) != 0) 4495d9e728a2Sgjelinek zerror(gettext("%s is not an XML file"), 4496d9e728a2Sgjelinek manifest_path); 4497d9e728a2Sgjelinek else 4498d9e728a2Sgjelinek zerror(gettext("Cannot attach to an earlier " 4499d9e728a2Sgjelinek "release of the operating system")); 4500d9e728a2Sgjelinek } else { 4501d9e728a2Sgjelinek zperror(cmd_to_str(CMD_ATTACH), B_TRUE); 4502d9e728a2Sgjelinek } 45038cd327d5Sgjelinek goto done; 45048cd327d5Sgjelinek } 45058cd327d5Sgjelinek 4506ff17c8bfSgjelinek /* Retrieve remote handle brand type. */ 4507e2482d1aSgjelinek if (zonecfg_get_brand(rem_handle, target_brand, sizeof (target_brand)) 4508e2482d1aSgjelinek != Z_OK) { 4509e2482d1aSgjelinek zerror(gettext("missing or invalid brand")); 4510e2482d1aSgjelinek exit(Z_ERR); 4511e2482d1aSgjelinek } 45128cd327d5Sgjelinek 45138cd327d5Sgjelinek done: 45148cd327d5Sgjelinek zonecfg_fini_handle(local_handle); 45158cd327d5Sgjelinek zonecfg_fini_handle(rem_handle); 4516ff17c8bfSgjelinek (void) close(fd); 45178cd327d5Sgjelinek 45188cd327d5Sgjelinek return ((res == Z_OK) ? Z_OK : Z_ERR); 45198cd327d5Sgjelinek } 45208cd327d5Sgjelinek 45216cfd72c6Sgjelinek /* ARGSUSED */ 4522ee519a1fSgjelinek static int 4523ee519a1fSgjelinek attach_func(int argc, char *argv[]) 4524ee519a1fSgjelinek { 452571443f5aS int lockfd = -1; 4526ee519a1fSgjelinek int err, arg; 4527ee519a1fSgjelinek boolean_t force = B_FALSE; 4528ee519a1fSgjelinek zone_dochandle_t handle; 4529ee519a1fSgjelinek char zonepath[MAXPATHLEN]; 453037774979Sgjelinek char cmdbuf[MAXPATHLEN]; 4531ff17c8bfSgjelinek char postcmdbuf[MAXPATHLEN]; 45328cd327d5Sgjelinek boolean_t execute = B_TRUE; 4533ff17c8bfSgjelinek boolean_t brand_help = B_FALSE; 45348cd327d5Sgjelinek char *manifest_path; 4535ff17c8bfSgjelinek char tmpmanifest[80]; 4536ff17c8bfSgjelinek int manifest_pos; 453737774979Sgjelinek brand_handle_t bh = NULL; 4538ff17c8bfSgjelinek int status; 4539edfa49ffS int last_index = 0; 4540edfa49ffS int offset; 4541edfa49ffS char *up; 4542edfa49ffS boolean_t forced_update = B_FALSE; 4543ee519a1fSgjelinek 4544ee519a1fSgjelinek if (zonecfg_in_alt_root()) { 4545ee519a1fSgjelinek zerror(gettext("cannot attach zone in alternate root")); 4546ee519a1fSgjelinek return (Z_ERR); 4547ee519a1fSgjelinek } 4548ee519a1fSgjelinek 4549ff17c8bfSgjelinek /* Check the argv string for args we handle internally */ 4550ee519a1fSgjelinek optind = 0; 4551ff17c8bfSgjelinek opterr = 0; 4552edfa49ffS while ((arg = getopt(argc, argv, "?Fn:U")) != EOF) { 4553ee519a1fSgjelinek switch (arg) { 4554ee519a1fSgjelinek case '?': 4555ff17c8bfSgjelinek if (optopt == '?') { 4556ee519a1fSgjelinek sub_usage(SHELP_ATTACH, CMD_ATTACH); 4557ff17c8bfSgjelinek brand_help = B_TRUE; 4558ff17c8bfSgjelinek } 4559ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 4560ff17c8bfSgjelinek break; 4561ee519a1fSgjelinek case 'F': 4562ee519a1fSgjelinek force = B_TRUE; 4563ee519a1fSgjelinek break; 45648cd327d5Sgjelinek case 'n': 45658cd327d5Sgjelinek execute = B_FALSE; 45668cd327d5Sgjelinek manifest_path = optarg; 4567ff17c8bfSgjelinek manifest_pos = optind - 1; 45686cfd72c6Sgjelinek break; 4569edfa49ffS case 'U': 4570edfa49ffS /* 4571edfa49ffS * Undocumented 'force update' option for p2v update on 4572edfa49ffS * attach when zone is in the incomplete state. Change 4573edfa49ffS * the option back to 'u' and set forced_update flag. 4574edfa49ffS */ 4575edfa49ffS if (optind == last_index) 4576edfa49ffS offset = optind; 4577edfa49ffS else 4578edfa49ffS offset = optind - 1; 4579edfa49ffS if ((up = index(argv[offset], 'U')) != NULL) 4580edfa49ffS *up = 'u'; 4581edfa49ffS forced_update = B_TRUE; 4582edfa49ffS break; 4583ee519a1fSgjelinek default: 4584ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 4585ff17c8bfSgjelinek break; 4586ee519a1fSgjelinek } 4587edfa49ffS last_index = optind; 4588ee519a1fSgjelinek } 45898cd327d5Sgjelinek 4590ff17c8bfSgjelinek if (brand_help) { 4591ff17c8bfSgjelinek force = B_FALSE; 4592ff17c8bfSgjelinek execute = B_TRUE; 4593ff17c8bfSgjelinek } 4594ff17c8bfSgjelinek 4595ff17c8bfSgjelinek /* dry-run and force flags are mutually exclusive */ 4596ff17c8bfSgjelinek if (!execute && force) { 4597ff17c8bfSgjelinek zerror(gettext("-F and -n flags are mutually exclusive")); 45986cfd72c6Sgjelinek return (Z_ERR); 45996cfd72c6Sgjelinek } 46006cfd72c6Sgjelinek 46018cd327d5Sgjelinek /* 4602ff17c8bfSgjelinek * If the no-execute option was specified, we don't do validation and 4603ff17c8bfSgjelinek * need to figure out the brand, since there is no zone required to be 46048cd327d5Sgjelinek * configured for this option. 46058cd327d5Sgjelinek */ 4606ff17c8bfSgjelinek if (execute) { 4607ff17c8bfSgjelinek if (!brand_help) { 4608ff17c8bfSgjelinek if (sanity_check(target_zone, CMD_ATTACH, B_FALSE, 4609edfa49ffS B_TRUE, forced_update) != Z_OK) 4610ee519a1fSgjelinek return (Z_ERR); 4611ce28b40eSzt129084 if (verify_details(CMD_ATTACH, argv) != Z_OK) 4612ee519a1fSgjelinek return (Z_ERR); 4613ff17c8bfSgjelinek } 4614ee519a1fSgjelinek 4615ff17c8bfSgjelinek if ((err = zone_get_zonepath(target_zone, zonepath, 4616ff17c8bfSgjelinek sizeof (zonepath))) != Z_OK) { 4617ee519a1fSgjelinek errno = err; 4618ff17c8bfSgjelinek zperror2(target_zone, 4619ff17c8bfSgjelinek gettext("could not get zone path")); 4620ee519a1fSgjelinek return (Z_ERR); 4621ee519a1fSgjelinek } 4622ff17c8bfSgjelinek } else { 4623ff17c8bfSgjelinek if (dryrun_get_brand(manifest_path, tmpmanifest, 4624ff17c8bfSgjelinek sizeof (tmpmanifest)) != Z_OK) 4625ff17c8bfSgjelinek return (Z_ERR); 4626ff17c8bfSgjelinek 4627ff17c8bfSgjelinek argv[manifest_pos] = tmpmanifest; 4628ff17c8bfSgjelinek target_zone = "-"; 4629ff17c8bfSgjelinek (void) strlcpy(zonepath, "-", sizeof (zonepath)); 4630ff17c8bfSgjelinek 4631ff17c8bfSgjelinek /* Run the brand's verify_adm hook. */ 4632ff17c8bfSgjelinek if (verify_brand(NULL, CMD_ATTACH, argv) != Z_OK) 4633ff17c8bfSgjelinek return (Z_ERR); 4634ff17c8bfSgjelinek } 4635ff17c8bfSgjelinek 4636ff17c8bfSgjelinek /* 4637ff17c8bfSgjelinek * Fetch the attach and postattach hooks from the brand configuration. 4638ff17c8bfSgjelinek */ 463937774979Sgjelinek if ((bh = brand_open(target_brand)) == NULL) { 464037774979Sgjelinek zerror(gettext("missing or invalid brand")); 464137774979Sgjelinek return (Z_ERR); 464237774979Sgjelinek } 464337774979Sgjelinek 4644ff17c8bfSgjelinek if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_attach, target_zone, 4645ff17c8bfSgjelinek zonepath) != Z_OK) { 4646ff17c8bfSgjelinek zerror("invalid brand configuration: missing attach resource"); 4647ff17c8bfSgjelinek brand_close(bh); 4648ff17c8bfSgjelinek return (Z_ERR); 4649ff17c8bfSgjelinek } 4650ff17c8bfSgjelinek 4651ff17c8bfSgjelinek if (get_hook(bh, postcmdbuf, sizeof (postcmdbuf), brand_get_postattach, 4652ff17c8bfSgjelinek target_zone, zonepath) != Z_OK) { 465337774979Sgjelinek zerror("invalid brand configuration: missing postattach " 465437774979Sgjelinek "resource"); 465537774979Sgjelinek brand_close(bh); 465637774979Sgjelinek return (Z_ERR); 465737774979Sgjelinek } 465837774979Sgjelinek brand_close(bh); 465937774979Sgjelinek 4660ff17c8bfSgjelinek /* Append all options to attach hook. */ 4661ff17c8bfSgjelinek if (addoptions(cmdbuf, argv, sizeof (cmdbuf)) != Z_OK) 466237774979Sgjelinek return (Z_ERR); 466337774979Sgjelinek 4664ff17c8bfSgjelinek /* Append all options to postattach hook. */ 4665ff17c8bfSgjelinek if (addoptions(postcmdbuf, argv, sizeof (postcmdbuf)) != Z_OK) 4666ff17c8bfSgjelinek return (Z_ERR); 4667ff17c8bfSgjelinek 4668ff17c8bfSgjelinek if (execute && !brand_help) { 4669ff17c8bfSgjelinek if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) { 4670ff17c8bfSgjelinek zerror(gettext("another %s may have an operation in " 4671ff17c8bfSgjelinek "progress."), "zoneadm"); 4672ee519a1fSgjelinek return (Z_ERR); 4673ee519a1fSgjelinek } 4674ff17c8bfSgjelinek } 4675ee519a1fSgjelinek 467671443f5aS if (!force) { 467771443f5aS /* 467871443f5aS * Not a force-attach, so we need to actually do the work. 467971443f5aS */ 4680ff17c8bfSgjelinek if (cmdbuf[0] != '\0') { 4681ff17c8bfSgjelinek /* Run the attach hook */ 4682edfa49ffS status = do_subproc(cmdbuf); 468371443f5aS if ((status = subproc_status(gettext("brand-specific " 468471443f5aS "attach"), status, B_FALSE)) != ZONE_SUBPROC_OK) { 4685ff17c8bfSgjelinek if (status == ZONE_SUBPROC_USAGE && !brand_help) 4686ff17c8bfSgjelinek sub_usage(SHELP_ATTACH, CMD_ATTACH); 4687ff17c8bfSgjelinek 468871443f5aS if (execute && !brand_help) { 4689edfa49ffS assert(zonecfg_lock_file_held(&lockfd)); 469071443f5aS zonecfg_release_lock_file(target_zone, 469171443f5aS lockfd); 469271443f5aS lockfd = -1; 4693ee519a1fSgjelinek } 4694ee519a1fSgjelinek 469571443f5aS assert(lockfd == -1); 469671443f5aS return (Z_ERR); 469771443f5aS } 4698ee519a1fSgjelinek } 4699ee519a1fSgjelinek 47009acbbeafSnn35248 /* 4701ff17c8bfSgjelinek * Else run the built-in attach support. 4702ff17c8bfSgjelinek * This is a no-op since there is nothing to validate. 47039acbbeafSnn35248 */ 4704ff17c8bfSgjelinek 4705ff17c8bfSgjelinek /* If dry-run or help, then we're done. */ 4706ff17c8bfSgjelinek if (!execute || brand_help) { 4707ff17c8bfSgjelinek if (!execute) 4708ff17c8bfSgjelinek (void) unlink(tmpmanifest); 470971443f5aS assert(lockfd == -1); 4710ff17c8bfSgjelinek return (Z_OK); 47119acbbeafSnn35248 } 471271443f5aS } 47139acbbeafSnn35248 4714ca733e25S /* Now we can validate that the zonepath exists. */ 4715ca733e25S if (validate_zonepath(zonepath, CMD_ATTACH) != Z_OK) { 4716ca733e25S (void) fprintf(stderr, gettext("could not verify zonepath %s " 4717ca733e25S "because of the above errors.\n"), zonepath); 4718ca733e25S 4719ca733e25S assert(zonecfg_lock_file_held(&lockfd)); 4720ca733e25S zonecfg_release_lock_file(target_zone, lockfd); 4721ca733e25S return (Z_ERR); 4722ca733e25S } 4723ca733e25S 472471443f5aS if ((handle = zonecfg_init_handle()) == NULL) { 472571443f5aS zperror(cmd_to_str(CMD_ATTACH), B_TRUE); 472671443f5aS err = Z_ERR; 472771443f5aS } else if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 472871443f5aS errno = err; 472971443f5aS zperror(cmd_to_str(CMD_ATTACH), B_TRUE); 473071443f5aS zonecfg_fini_handle(handle); 473171443f5aS } else { 4732ee519a1fSgjelinek zonecfg_rm_detached(handle, force); 473371443f5aS zonecfg_fini_handle(handle); 473471443f5aS } 4735ee519a1fSgjelinek 473671443f5aS if (err == Z_OK && 473771443f5aS (err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) { 4738ee519a1fSgjelinek errno = err; 4739ee519a1fSgjelinek zperror(gettext("could not reset state"), B_TRUE); 4740ee519a1fSgjelinek } 4741ee519a1fSgjelinek 4742edfa49ffS assert(zonecfg_lock_file_held(&lockfd)); 4743ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 474471443f5aS lockfd = -1; 4745ee519a1fSgjelinek 474637774979Sgjelinek /* If we have a brand postattach hook, run it. */ 4747ff17c8bfSgjelinek if (err == Z_OK && !force && postcmdbuf[0] != '\0') { 4748ff17c8bfSgjelinek status = do_subproc(postcmdbuf); 474937774979Sgjelinek if (subproc_status(gettext("brand-specific postattach"), 475037774979Sgjelinek status, B_FALSE) != ZONE_SUBPROC_OK) { 475137774979Sgjelinek if ((err = zone_set_state(target_zone, 475237774979Sgjelinek ZONE_STATE_CONFIGURED)) != Z_OK) { 475337774979Sgjelinek errno = err; 475437774979Sgjelinek zperror(gettext("could not reset state"), 475537774979Sgjelinek B_TRUE); 475637774979Sgjelinek } 475737774979Sgjelinek } 475837774979Sgjelinek } 475937774979Sgjelinek 476071443f5aS assert(lockfd == -1); 4761ee519a1fSgjelinek return ((err == Z_OK) ? Z_OK : Z_ERR); 4762ee519a1fSgjelinek } 4763ee519a1fSgjelinek 4764865e09a4Sgjelinek /* 47657c478bd9Sstevel@tonic-gate * On input, TRUE => yes, FALSE => no. 47667c478bd9Sstevel@tonic-gate * On return, TRUE => 1, FALSE => 0, could not ask => -1. 47677c478bd9Sstevel@tonic-gate */ 47687c478bd9Sstevel@tonic-gate 47697c478bd9Sstevel@tonic-gate static int 47707c478bd9Sstevel@tonic-gate ask_yesno(boolean_t default_answer, const char *question) 47717c478bd9Sstevel@tonic-gate { 47727c478bd9Sstevel@tonic-gate char line[64]; /* should be large enough to answer yes or no */ 47737c478bd9Sstevel@tonic-gate 47747c478bd9Sstevel@tonic-gate if (!isatty(STDIN_FILENO)) 47757c478bd9Sstevel@tonic-gate return (-1); 47767c478bd9Sstevel@tonic-gate for (;;) { 47777c478bd9Sstevel@tonic-gate (void) printf("%s (%s)? ", question, 47787c478bd9Sstevel@tonic-gate default_answer ? "[y]/n" : "y/[n]"); 47797c478bd9Sstevel@tonic-gate if (fgets(line, sizeof (line), stdin) == NULL || 47807c478bd9Sstevel@tonic-gate line[0] == '\n') 47817c478bd9Sstevel@tonic-gate return (default_answer ? 1 : 0); 47827c478bd9Sstevel@tonic-gate if (tolower(line[0]) == 'y') 47837c478bd9Sstevel@tonic-gate return (1); 47847c478bd9Sstevel@tonic-gate if (tolower(line[0]) == 'n') 47857c478bd9Sstevel@tonic-gate return (0); 47867c478bd9Sstevel@tonic-gate } 47877c478bd9Sstevel@tonic-gate } 47887c478bd9Sstevel@tonic-gate 4789ff17c8bfSgjelinek /* ARGSUSED */ 47907c478bd9Sstevel@tonic-gate static int 47917c478bd9Sstevel@tonic-gate uninstall_func(int argc, char *argv[]) 47927c478bd9Sstevel@tonic-gate { 47937c478bd9Sstevel@tonic-gate char line[ZONENAME_MAX + 128]; /* Enough for "Are you sure ..." */ 47940b5de56dSgjelinek char rootpath[MAXPATHLEN], zonepath[MAXPATHLEN]; 479537774979Sgjelinek char cmdbuf[MAXPATHLEN]; 4796ff17c8bfSgjelinek char precmdbuf[MAXPATHLEN]; 47977c478bd9Sstevel@tonic-gate boolean_t force = B_FALSE; 47987c478bd9Sstevel@tonic-gate int lockfd, answer; 47997c478bd9Sstevel@tonic-gate int err, arg; 4800ff17c8bfSgjelinek boolean_t brand_help = B_FALSE; 480137774979Sgjelinek brand_handle_t bh = NULL; 4802ff17c8bfSgjelinek int status; 48037c478bd9Sstevel@tonic-gate 4804108322fbScarlsonj if (zonecfg_in_alt_root()) { 4805108322fbScarlsonj zerror(gettext("cannot uninstall zone in alternate root")); 4806108322fbScarlsonj return (Z_ERR); 4807108322fbScarlsonj } 4808108322fbScarlsonj 4809ff17c8bfSgjelinek /* Check the argv string for args we handle internally */ 48107c478bd9Sstevel@tonic-gate optind = 0; 4811ff17c8bfSgjelinek opterr = 0; 48127c478bd9Sstevel@tonic-gate while ((arg = getopt(argc, argv, "?F")) != EOF) { 48137c478bd9Sstevel@tonic-gate switch (arg) { 48147c478bd9Sstevel@tonic-gate case '?': 4815ff17c8bfSgjelinek if (optopt == '?') { 48167c478bd9Sstevel@tonic-gate sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL); 4817ff17c8bfSgjelinek brand_help = B_TRUE; 4818ff17c8bfSgjelinek } 4819ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 4820ff17c8bfSgjelinek break; 48217c478bd9Sstevel@tonic-gate case 'F': 48227c478bd9Sstevel@tonic-gate force = B_TRUE; 48237c478bd9Sstevel@tonic-gate break; 48247c478bd9Sstevel@tonic-gate default: 4825ff17c8bfSgjelinek /* Ignore unknown options - may be brand specific. */ 4826ff17c8bfSgjelinek break; 48277c478bd9Sstevel@tonic-gate } 48287c478bd9Sstevel@tonic-gate } 48297c478bd9Sstevel@tonic-gate 4830ff17c8bfSgjelinek if (!brand_help) { 4831ff17c8bfSgjelinek if (sanity_check(target_zone, CMD_UNINSTALL, B_FALSE, B_TRUE, 4832ff17c8bfSgjelinek B_FALSE) != Z_OK) 48337c478bd9Sstevel@tonic-gate return (Z_ERR); 48347c478bd9Sstevel@tonic-gate 4835ce28b40eSzt129084 /* 4836ce28b40eSzt129084 * Invoke brand-specific handler. 4837ce28b40eSzt129084 */ 4838ce28b40eSzt129084 if (invoke_brand_handler(CMD_UNINSTALL, argv) != Z_OK) 4839ce28b40eSzt129084 return (Z_ERR); 4840ce28b40eSzt129084 48417c478bd9Sstevel@tonic-gate if (!force) { 48427c478bd9Sstevel@tonic-gate (void) snprintf(line, sizeof (line), 48437c478bd9Sstevel@tonic-gate gettext("Are you sure you want to %s zone %s"), 48447c478bd9Sstevel@tonic-gate cmd_to_str(CMD_UNINSTALL), target_zone); 48457c478bd9Sstevel@tonic-gate if ((answer = ask_yesno(B_FALSE, line)) == 0) { 48467c478bd9Sstevel@tonic-gate return (Z_OK); 48477c478bd9Sstevel@tonic-gate } else if (answer == -1) { 48487c478bd9Sstevel@tonic-gate zerror(gettext("Input not from terminal and -F " 48497c478bd9Sstevel@tonic-gate "not specified: %s not done."), 48507c478bd9Sstevel@tonic-gate cmd_to_str(CMD_UNINSTALL)); 48517c478bd9Sstevel@tonic-gate return (Z_ERR); 48527c478bd9Sstevel@tonic-gate } 48537c478bd9Sstevel@tonic-gate } 4854ff17c8bfSgjelinek } 48557c478bd9Sstevel@tonic-gate 48560b5de56dSgjelinek if ((err = zone_get_zonepath(target_zone, zonepath, 48570b5de56dSgjelinek sizeof (zonepath))) != Z_OK) { 48587c478bd9Sstevel@tonic-gate errno = err; 48597c478bd9Sstevel@tonic-gate zperror2(target_zone, gettext("could not get zone path")); 48607c478bd9Sstevel@tonic-gate return (Z_ERR); 48617c478bd9Sstevel@tonic-gate } 4862ff17c8bfSgjelinek 4863ff17c8bfSgjelinek /* 4864ff17c8bfSgjelinek * Fetch the uninstall and preuninstall hooks from the brand 4865ff17c8bfSgjelinek * configuration. 4866ff17c8bfSgjelinek */ 4867ff17c8bfSgjelinek if ((bh = brand_open(target_brand)) == NULL) { 4868ff17c8bfSgjelinek zerror(gettext("missing or invalid brand")); 4869ff17c8bfSgjelinek return (Z_ERR); 4870ff17c8bfSgjelinek } 4871ff17c8bfSgjelinek 4872ff17c8bfSgjelinek if (get_hook(bh, cmdbuf, sizeof (cmdbuf), brand_get_uninstall, 4873ff17c8bfSgjelinek target_zone, zonepath) != Z_OK) { 4874ff17c8bfSgjelinek zerror("invalid brand configuration: missing uninstall " 4875ff17c8bfSgjelinek "resource"); 4876ff17c8bfSgjelinek brand_close(bh); 4877ff17c8bfSgjelinek return (Z_ERR); 4878ff17c8bfSgjelinek } 4879ff17c8bfSgjelinek 4880ff17c8bfSgjelinek if (get_hook(bh, precmdbuf, sizeof (precmdbuf), brand_get_preuninstall, 4881ff17c8bfSgjelinek target_zone, zonepath) != Z_OK) { 4882ff17c8bfSgjelinek zerror("invalid brand configuration: missing preuninstall " 4883ff17c8bfSgjelinek "resource"); 4884ff17c8bfSgjelinek brand_close(bh); 4885ff17c8bfSgjelinek return (Z_ERR); 4886ff17c8bfSgjelinek } 4887ff17c8bfSgjelinek brand_close(bh); 4888ff17c8bfSgjelinek 4889ff17c8bfSgjelinek /* Append all options to preuninstall hook. */ 4890ff17c8bfSgjelinek if (addoptions(precmdbuf, argv, sizeof (precmdbuf)) != Z_OK) 4891ff17c8bfSgjelinek return (Z_ERR); 4892ff17c8bfSgjelinek 4893ff17c8bfSgjelinek /* Append all options to uninstall hook. */ 4894ff17c8bfSgjelinek if (addoptions(cmdbuf, argv, sizeof (cmdbuf)) != Z_OK) 4895ff17c8bfSgjelinek return (Z_ERR); 4896ff17c8bfSgjelinek 4897ff17c8bfSgjelinek if (!brand_help) { 48987c478bd9Sstevel@tonic-gate if ((err = zone_get_rootpath(target_zone, rootpath, 48997c478bd9Sstevel@tonic-gate sizeof (rootpath))) != Z_OK) { 49007c478bd9Sstevel@tonic-gate errno = err; 4901ff17c8bfSgjelinek zperror2(target_zone, gettext("could not get root " 4902ff17c8bfSgjelinek "path")); 49037c478bd9Sstevel@tonic-gate return (Z_ERR); 49047c478bd9Sstevel@tonic-gate } 49057c478bd9Sstevel@tonic-gate 49067c478bd9Sstevel@tonic-gate /* 4907ff17c8bfSgjelinek * If there seems to be a zoneadmd running for this zone, call 4908ff17c8bfSgjelinek * it to tell it that an uninstall is happening; if all goes 4909ff17c8bfSgjelinek * well it will then shut itself down. 49107c478bd9Sstevel@tonic-gate */ 4911ff17c8bfSgjelinek if (zonecfg_ping_zoneadmd(target_zone) == Z_OK) { 49127c478bd9Sstevel@tonic-gate zone_cmd_arg_t zarg; 49137c478bd9Sstevel@tonic-gate zarg.cmd = Z_NOTE_UNINSTALLING; 4914ff17c8bfSgjelinek /* we don't care too much if this fails, just plow on */ 4915ff17c8bfSgjelinek (void) zonecfg_call_zoneadmd(target_zone, &zarg, locale, 4916ff17c8bfSgjelinek B_TRUE); 49177c478bd9Sstevel@tonic-gate } 49187c478bd9Sstevel@tonic-gate 4919ff17c8bfSgjelinek if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) { 4920ff17c8bfSgjelinek zerror(gettext("another %s may have an operation in " 4921ff17c8bfSgjelinek "progress."), "zoneadm"); 49227c478bd9Sstevel@tonic-gate return (Z_ERR); 49237c478bd9Sstevel@tonic-gate } 49247c478bd9Sstevel@tonic-gate 49257c478bd9Sstevel@tonic-gate /* Don't uninstall the zone if anything is mounted there */ 49267c478bd9Sstevel@tonic-gate err = zonecfg_find_mounts(rootpath, NULL, NULL); 49277c478bd9Sstevel@tonic-gate if (err) { 49280b5de56dSgjelinek zerror(gettext("These file systems are mounted on " 49297c478bd9Sstevel@tonic-gate "subdirectories of %s.\n"), rootpath); 49307c478bd9Sstevel@tonic-gate (void) zonecfg_find_mounts(rootpath, zfm_print, NULL); 4931ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 49327c478bd9Sstevel@tonic-gate return (Z_ERR); 49337c478bd9Sstevel@tonic-gate } 493437774979Sgjelinek } 493537774979Sgjelinek 4936ff17c8bfSgjelinek /* If we have a brand preuninstall hook, run it. */ 4937ff17c8bfSgjelinek if (!brand_help && precmdbuf[0] != '\0') { 4938ab5dfd5eS status = do_subproc(precmdbuf); 493937774979Sgjelinek if (subproc_status(gettext("brand-specific preuninstall"), 494037774979Sgjelinek status, B_FALSE) != ZONE_SUBPROC_OK) { 4941ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 494237774979Sgjelinek return (Z_ERR); 494337774979Sgjelinek } 494437774979Sgjelinek } 494537774979Sgjelinek 4946ff17c8bfSgjelinek if (!brand_help) { 49477c478bd9Sstevel@tonic-gate err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE); 49487c478bd9Sstevel@tonic-gate if (err != Z_OK) { 49497c478bd9Sstevel@tonic-gate errno = err; 49507c478bd9Sstevel@tonic-gate zperror2(target_zone, gettext("could not set state")); 49517c478bd9Sstevel@tonic-gate goto bad; 49527c478bd9Sstevel@tonic-gate } 4953ff17c8bfSgjelinek } 49547c478bd9Sstevel@tonic-gate 4955ff17c8bfSgjelinek /* 4956ff17c8bfSgjelinek * If there is a brand uninstall hook, use it, otherwise use the 4957ff17c8bfSgjelinek * built-in uninstall code. 4958ff17c8bfSgjelinek */ 4959ff17c8bfSgjelinek if (cmdbuf[0] != '\0') { 4960ff17c8bfSgjelinek /* Run the uninstall hook */ 4961c75cc341S status = do_subproc(cmdbuf); 4962ff17c8bfSgjelinek if ((status = subproc_status(gettext("brand-specific " 4963ff17c8bfSgjelinek "uninstall"), status, B_FALSE)) != ZONE_SUBPROC_OK) { 4964ff17c8bfSgjelinek if (status == ZONE_SUBPROC_USAGE && !brand_help) 4965ff17c8bfSgjelinek sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL); 4966ff17c8bfSgjelinek if (!brand_help) 4967ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 4968ff17c8bfSgjelinek return (Z_ERR); 4969ff17c8bfSgjelinek } 4970ff17c8bfSgjelinek 4971ff17c8bfSgjelinek if (brand_help) 4972ff17c8bfSgjelinek return (Z_OK); 4973ff17c8bfSgjelinek } else { 4974ff17c8bfSgjelinek /* If just help, we're done since there is no brand help. */ 4975ff17c8bfSgjelinek if (brand_help) 4976ff17c8bfSgjelinek return (Z_OK); 4977ff17c8bfSgjelinek 4978ff17c8bfSgjelinek /* Run the built-in uninstall support. */ 49790b5de56dSgjelinek if ((err = cleanup_zonepath(zonepath, B_FALSE)) != Z_OK) { 49800b5de56dSgjelinek errno = err; 4981ff17c8bfSgjelinek zperror2(target_zone, gettext("cleaning up zonepath " 4982ff17c8bfSgjelinek "failed")); 49837c478bd9Sstevel@tonic-gate goto bad; 49840b5de56dSgjelinek } 4985ff17c8bfSgjelinek } 49860b5de56dSgjelinek 49877c478bd9Sstevel@tonic-gate err = zone_set_state(target_zone, ZONE_STATE_CONFIGURED); 49887c478bd9Sstevel@tonic-gate if (err != Z_OK) { 49897c478bd9Sstevel@tonic-gate errno = err; 49907c478bd9Sstevel@tonic-gate zperror2(target_zone, gettext("could not reset state")); 49917c478bd9Sstevel@tonic-gate } 49927c478bd9Sstevel@tonic-gate bad: 4993ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 49947c478bd9Sstevel@tonic-gate return (err); 49957c478bd9Sstevel@tonic-gate } 49967c478bd9Sstevel@tonic-gate 4997108322fbScarlsonj /* ARGSUSED */ 4998108322fbScarlsonj static int 4999108322fbScarlsonj mount_func(int argc, char *argv[]) 5000108322fbScarlsonj { 5001108322fbScarlsonj zone_cmd_arg_t zarg; 50029acbbeafSnn35248 boolean_t force = B_FALSE; 50039acbbeafSnn35248 int arg; 5004108322fbScarlsonj 50059acbbeafSnn35248 /* 50069acbbeafSnn35248 * The only supported subargument to the "mount" subcommand is 50079acbbeafSnn35248 * "-f", which forces us to mount a zone in the INCOMPLETE state. 50089acbbeafSnn35248 */ 50099acbbeafSnn35248 optind = 0; 50109acbbeafSnn35248 if ((arg = getopt(argc, argv, "f")) != EOF) { 50119acbbeafSnn35248 switch (arg) { 50129acbbeafSnn35248 case 'f': 50139acbbeafSnn35248 force = B_TRUE; 50149acbbeafSnn35248 break; 50159acbbeafSnn35248 default: 5016108322fbScarlsonj return (Z_USAGE); 50179acbbeafSnn35248 } 50189acbbeafSnn35248 } 50199acbbeafSnn35248 if (argc > optind) 50209acbbeafSnn35248 return (Z_USAGE); 50219acbbeafSnn35248 50229acbbeafSnn35248 if (sanity_check(target_zone, CMD_MOUNT, B_FALSE, B_FALSE, force) 50239acbbeafSnn35248 != Z_OK) 5024108322fbScarlsonj return (Z_ERR); 5025ce28b40eSzt129084 if (verify_details(CMD_MOUNT, argv) != Z_OK) 5026108322fbScarlsonj return (Z_ERR); 5027108322fbScarlsonj 50289acbbeafSnn35248 zarg.cmd = force ? Z_FORCEMOUNT : Z_MOUNT; 50296cfd72c6Sgjelinek zarg.bootbuf[0] = '\0'; 5030ff17c8bfSgjelinek if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) { 5031108322fbScarlsonj zerror(gettext("call to %s failed"), "zoneadmd"); 5032108322fbScarlsonj return (Z_ERR); 5033108322fbScarlsonj } 5034108322fbScarlsonj return (Z_OK); 5035108322fbScarlsonj } 5036108322fbScarlsonj 5037108322fbScarlsonj /* ARGSUSED */ 5038108322fbScarlsonj static int 5039108322fbScarlsonj unmount_func(int argc, char *argv[]) 5040108322fbScarlsonj { 5041108322fbScarlsonj zone_cmd_arg_t zarg; 5042108322fbScarlsonj 5043108322fbScarlsonj if (argc > 0) 5044108322fbScarlsonj return (Z_USAGE); 50459acbbeafSnn35248 if (sanity_check(target_zone, CMD_UNMOUNT, B_FALSE, B_FALSE, B_FALSE) 50469acbbeafSnn35248 != Z_OK) 5047108322fbScarlsonj return (Z_ERR); 5048108322fbScarlsonj 5049108322fbScarlsonj zarg.cmd = Z_UNMOUNT; 5050ff17c8bfSgjelinek if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != 0) { 5051108322fbScarlsonj zerror(gettext("call to %s failed"), "zoneadmd"); 5052108322fbScarlsonj return (Z_ERR); 5053108322fbScarlsonj } 5054108322fbScarlsonj return (Z_OK); 5055108322fbScarlsonj } 5056108322fbScarlsonj 50577c478bd9Sstevel@tonic-gate static int 5058555afedfScarlsonj mark_func(int argc, char *argv[]) 5059555afedfScarlsonj { 5060555afedfScarlsonj int err, lockfd; 5061edfa49ffS int arg; 5062edfa49ffS boolean_t force = B_FALSE; 5063edfa49ffS int state; 5064555afedfScarlsonj 5065edfa49ffS optind = 0; 5066edfa49ffS opterr = 0; 5067edfa49ffS while ((arg = getopt(argc, argv, "F")) != EOF) { 5068edfa49ffS switch (arg) { 5069edfa49ffS case 'F': 5070edfa49ffS force = B_TRUE; 5071edfa49ffS break; 5072edfa49ffS default: 5073555afedfScarlsonj return (Z_USAGE); 5074edfa49ffS } 5075edfa49ffS } 5076edfa49ffS 5077edfa49ffS if (argc != (optind + 1)) 5078edfa49ffS return (Z_USAGE); 5079edfa49ffS 5080edfa49ffS if (strcmp(argv[optind], "configured") == 0) 5081edfa49ffS state = ZONE_STATE_CONFIGURED; 5082edfa49ffS else if (strcmp(argv[optind], "incomplete") == 0) 5083edfa49ffS state = ZONE_STATE_INCOMPLETE; 5084edfa49ffS else if (strcmp(argv[optind], "installed") == 0) 5085edfa49ffS state = ZONE_STATE_INSTALLED; 5086edfa49ffS else 5087edfa49ffS return (Z_USAGE); 5088edfa49ffS 5089edfa49ffS if (state != ZONE_STATE_INCOMPLETE && !force) 5090edfa49ffS return (Z_USAGE); 5091edfa49ffS 5092edfa49ffS if (sanity_check(target_zone, CMD_MARK, B_FALSE, B_TRUE, B_FALSE) 50939acbbeafSnn35248 != Z_OK) 5094555afedfScarlsonj return (Z_ERR); 5095555afedfScarlsonj 5096ce28b40eSzt129084 /* 5097ce28b40eSzt129084 * Invoke brand-specific handler. 5098ce28b40eSzt129084 */ 5099ce28b40eSzt129084 if (invoke_brand_handler(CMD_MARK, argv) != Z_OK) 5100ce28b40eSzt129084 return (Z_ERR); 5101ce28b40eSzt129084 5102ff17c8bfSgjelinek if (zonecfg_grab_lock_file(target_zone, &lockfd) != Z_OK) { 5103555afedfScarlsonj zerror(gettext("another %s may have an operation in progress."), 5104555afedfScarlsonj "zoneadm"); 5105555afedfScarlsonj return (Z_ERR); 5106555afedfScarlsonj } 5107555afedfScarlsonj 5108edfa49ffS err = zone_set_state(target_zone, state); 5109555afedfScarlsonj if (err != Z_OK) { 5110555afedfScarlsonj errno = err; 5111555afedfScarlsonj zperror2(target_zone, gettext("could not set state")); 5112555afedfScarlsonj } 5113ff17c8bfSgjelinek zonecfg_release_lock_file(target_zone, lockfd); 5114555afedfScarlsonj 5115555afedfScarlsonj return (err); 5116555afedfScarlsonj } 5117555afedfScarlsonj 51180209230bSgjelinek /* 51190209230bSgjelinek * Check what scheduling class we're running under and print a warning if 51200209230bSgjelinek * we're not using FSS. 51210209230bSgjelinek */ 51220209230bSgjelinek static int 51230209230bSgjelinek check_sched_fss(zone_dochandle_t handle) 51240209230bSgjelinek { 51250209230bSgjelinek char class_name[PC_CLNMSZ]; 51260209230bSgjelinek 51270209230bSgjelinek if (zonecfg_get_dflt_sched_class(handle, class_name, 51280209230bSgjelinek sizeof (class_name)) != Z_OK) { 51290209230bSgjelinek zerror(gettext("WARNING: unable to determine the zone's " 51300209230bSgjelinek "scheduling class")); 51310209230bSgjelinek } else if (strcmp("FSS", class_name) != 0) { 51320209230bSgjelinek zerror(gettext("WARNING: The zone.cpu-shares rctl is set but\n" 51330209230bSgjelinek "FSS is not the default scheduling class for this zone. " 51340209230bSgjelinek "FSS will be\nused for processes in the zone but to get " 51350209230bSgjelinek "the full benefit of FSS,\nit should be the default " 51360209230bSgjelinek "scheduling class. See dispadmin(1M) for\nmore details.")); 51370209230bSgjelinek return (Z_SYSTEM); 51380209230bSgjelinek } 51390209230bSgjelinek 51400209230bSgjelinek return (Z_OK); 51410209230bSgjelinek } 51420209230bSgjelinek 51430209230bSgjelinek static int 51440209230bSgjelinek check_cpu_shares_sched(zone_dochandle_t handle) 51450209230bSgjelinek { 51460209230bSgjelinek int err; 51470209230bSgjelinek int res = Z_OK; 51480209230bSgjelinek struct zone_rctltab rctl; 51490209230bSgjelinek 51500209230bSgjelinek if ((err = zonecfg_setrctlent(handle)) != Z_OK) { 51510209230bSgjelinek errno = err; 51520209230bSgjelinek zperror(cmd_to_str(CMD_APPLY), B_TRUE); 51530209230bSgjelinek return (err); 51540209230bSgjelinek } 51550209230bSgjelinek 51560209230bSgjelinek while (zonecfg_getrctlent(handle, &rctl) == Z_OK) { 51570209230bSgjelinek if (strcmp(rctl.zone_rctl_name, "zone.cpu-shares") == 0) { 51580209230bSgjelinek if (check_sched_fss(handle) != Z_OK) 51590209230bSgjelinek res = Z_SYSTEM; 51600209230bSgjelinek break; 51610209230bSgjelinek } 51620209230bSgjelinek } 51630209230bSgjelinek 51640209230bSgjelinek (void) zonecfg_endrctlent(handle); 51650209230bSgjelinek 51660209230bSgjelinek return (res); 51670209230bSgjelinek } 51680209230bSgjelinek 51690209230bSgjelinek /* 51707ef01d19Sgjelinek * Check if there is a mix of processes running in different pools within the 51717ef01d19Sgjelinek * zone. This is currently only going to be called for the global zone from 51727ef01d19Sgjelinek * apply_func but that could be generalized in the future. 51737ef01d19Sgjelinek */ 51747ef01d19Sgjelinek static boolean_t 51757ef01d19Sgjelinek mixed_pools(zoneid_t zoneid) 51767ef01d19Sgjelinek { 51777ef01d19Sgjelinek DIR *dirp; 51787ef01d19Sgjelinek dirent_t *dent; 51797ef01d19Sgjelinek boolean_t mixed = B_FALSE; 51807ef01d19Sgjelinek boolean_t poolid_set = B_FALSE; 51817ef01d19Sgjelinek poolid_t last_poolid = 0; 51827ef01d19Sgjelinek 51837ef01d19Sgjelinek if ((dirp = opendir("/proc")) == NULL) { 51847ef01d19Sgjelinek zerror(gettext("could not open /proc")); 51857ef01d19Sgjelinek return (B_FALSE); 51867ef01d19Sgjelinek } 51877ef01d19Sgjelinek 51887ef01d19Sgjelinek while ((dent = readdir(dirp)) != NULL) { 51897ef01d19Sgjelinek int procfd; 51907ef01d19Sgjelinek psinfo_t ps; 51917ef01d19Sgjelinek char procpath[MAXPATHLEN]; 51927ef01d19Sgjelinek 51937ef01d19Sgjelinek if (dent->d_name[0] == '.') 51947ef01d19Sgjelinek continue; 51957ef01d19Sgjelinek 51967ef01d19Sgjelinek (void) snprintf(procpath, sizeof (procpath), "/proc/%s/psinfo", 51977ef01d19Sgjelinek dent->d_name); 51987ef01d19Sgjelinek 51997ef01d19Sgjelinek if ((procfd = open(procpath, O_RDONLY)) == -1) 52007ef01d19Sgjelinek continue; 52017ef01d19Sgjelinek 52027ef01d19Sgjelinek if (read(procfd, &ps, sizeof (ps)) == sizeof (psinfo_t)) { 52037ef01d19Sgjelinek /* skip processes in other zones and system processes */ 52047ef01d19Sgjelinek if (zoneid != ps.pr_zoneid || ps.pr_flag & SSYS) { 52057ef01d19Sgjelinek (void) close(procfd); 52067ef01d19Sgjelinek continue; 52077ef01d19Sgjelinek } 52087ef01d19Sgjelinek 52097ef01d19Sgjelinek if (poolid_set) { 52107ef01d19Sgjelinek if (ps.pr_poolid != last_poolid) 52117ef01d19Sgjelinek mixed = B_TRUE; 52127ef01d19Sgjelinek } else { 52137ef01d19Sgjelinek last_poolid = ps.pr_poolid; 52147ef01d19Sgjelinek poolid_set = B_TRUE; 52157ef01d19Sgjelinek } 52167ef01d19Sgjelinek } 52177ef01d19Sgjelinek 52187ef01d19Sgjelinek (void) close(procfd); 52197ef01d19Sgjelinek 52207ef01d19Sgjelinek if (mixed) 52217ef01d19Sgjelinek break; 52227ef01d19Sgjelinek } 52237ef01d19Sgjelinek 52247ef01d19Sgjelinek (void) closedir(dirp); 52257ef01d19Sgjelinek 52267ef01d19Sgjelinek return (mixed); 52277ef01d19Sgjelinek } 52287ef01d19Sgjelinek 52297ef01d19Sgjelinek /* 52307ef01d19Sgjelinek * Check if a persistent or temporary pool is configured for the zone. 52317ef01d19Sgjelinek * This is currently only going to be called for the global zone from 52327ef01d19Sgjelinek * apply_func but that could be generalized in the future. 52337ef01d19Sgjelinek */ 52347ef01d19Sgjelinek static boolean_t 52357ef01d19Sgjelinek pool_configured(zone_dochandle_t handle) 52367ef01d19Sgjelinek { 52377ef01d19Sgjelinek int err1, err2; 52387ef01d19Sgjelinek struct zone_psettab pset_tab; 52397ef01d19Sgjelinek char poolname[MAXPATHLEN]; 52407ef01d19Sgjelinek 52417ef01d19Sgjelinek err1 = zonecfg_lookup_pset(handle, &pset_tab); 52427ef01d19Sgjelinek err2 = zonecfg_get_pool(handle, poolname, sizeof (poolname)); 52437ef01d19Sgjelinek 52447ef01d19Sgjelinek if (err1 == Z_NO_ENTRY && 52457ef01d19Sgjelinek (err2 == Z_NO_ENTRY || (err2 == Z_OK && strlen(poolname) == 0))) 52467ef01d19Sgjelinek return (B_FALSE); 52477ef01d19Sgjelinek 52487ef01d19Sgjelinek return (B_TRUE); 52497ef01d19Sgjelinek } 52507ef01d19Sgjelinek 52517ef01d19Sgjelinek /* 52520209230bSgjelinek * This is an undocumented interface which is currently only used to apply 52530209230bSgjelinek * the global zone resource management settings when the system boots. 52540209230bSgjelinek * This function does not yet properly handle updating a running system so 52550209230bSgjelinek * any projects running in the zone would be trashed if this function 52560209230bSgjelinek * were to run after the zone had booted. It also does not reset any 52570209230bSgjelinek * rctl settings that were removed from zonecfg. There is still work to be 52580209230bSgjelinek * done before we can properly support dynamically updating the resource 52590209230bSgjelinek * management settings for a running zone (global or non-global). Thus, this 52600209230bSgjelinek * functionality is undocumented for now. 52610209230bSgjelinek */ 52620209230bSgjelinek /* ARGSUSED */ 52630209230bSgjelinek static int 52640209230bSgjelinek apply_func(int argc, char *argv[]) 52650209230bSgjelinek { 52660209230bSgjelinek int err; 52670209230bSgjelinek int res = Z_OK; 52680209230bSgjelinek priv_set_t *privset; 52690209230bSgjelinek zoneid_t zoneid; 52700209230bSgjelinek zone_dochandle_t handle; 52710209230bSgjelinek struct zone_mcaptab mcap; 52720209230bSgjelinek char pool_err[128]; 52730209230bSgjelinek 52740209230bSgjelinek zoneid = getzoneid(); 52750209230bSgjelinek 52760209230bSgjelinek if (zonecfg_in_alt_root() || zoneid != GLOBAL_ZONEID || 52770209230bSgjelinek target_zone == NULL || strcmp(target_zone, GLOBAL_ZONENAME) != 0) 52780209230bSgjelinek return (usage(B_FALSE)); 52790209230bSgjelinek 52800209230bSgjelinek if ((privset = priv_allocset()) == NULL) { 52810209230bSgjelinek zerror(gettext("%s failed"), "priv_allocset"); 52820209230bSgjelinek return (Z_ERR); 52830209230bSgjelinek } 52840209230bSgjelinek 52850209230bSgjelinek if (getppriv(PRIV_EFFECTIVE, privset) != 0) { 52860209230bSgjelinek zerror(gettext("%s failed"), "getppriv"); 52870209230bSgjelinek priv_freeset(privset); 52880209230bSgjelinek return (Z_ERR); 52890209230bSgjelinek } 52900209230bSgjelinek 52910209230bSgjelinek if (priv_isfullset(privset) == B_FALSE) { 52920209230bSgjelinek (void) usage(B_FALSE); 52930209230bSgjelinek priv_freeset(privset); 52940209230bSgjelinek return (Z_ERR); 52950209230bSgjelinek } 52960209230bSgjelinek priv_freeset(privset); 52970209230bSgjelinek 52980209230bSgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 52990209230bSgjelinek zperror(cmd_to_str(CMD_APPLY), B_TRUE); 53000209230bSgjelinek return (Z_ERR); 53010209230bSgjelinek } 53020209230bSgjelinek 53030209230bSgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 53040209230bSgjelinek errno = err; 53050209230bSgjelinek zperror(cmd_to_str(CMD_APPLY), B_TRUE); 53060209230bSgjelinek zonecfg_fini_handle(handle); 53070209230bSgjelinek return (Z_ERR); 53080209230bSgjelinek } 53090209230bSgjelinek 53100209230bSgjelinek /* specific error msgs are printed within apply_rctls */ 53110209230bSgjelinek if ((err = zonecfg_apply_rctls(target_zone, handle)) != Z_OK) { 53120209230bSgjelinek errno = err; 53130209230bSgjelinek zperror(cmd_to_str(CMD_APPLY), B_TRUE); 53140209230bSgjelinek res = Z_ERR; 53150209230bSgjelinek } 53160209230bSgjelinek 53170209230bSgjelinek if ((err = check_cpu_shares_sched(handle)) != Z_OK) 53180209230bSgjelinek res = Z_ERR; 53190209230bSgjelinek 53207ef01d19Sgjelinek if (pool_configured(handle)) { 53217ef01d19Sgjelinek if (mixed_pools(zoneid)) { 53227ef01d19Sgjelinek zerror(gettext("Zone is using multiple resource " 53237ef01d19Sgjelinek "pools. The pool\nconfiguration cannot be " 53247ef01d19Sgjelinek "applied without rebooting.")); 53257ef01d19Sgjelinek res = Z_ERR; 53267ef01d19Sgjelinek } else { 53277ef01d19Sgjelinek 53280209230bSgjelinek /* 53297ef01d19Sgjelinek * The next two blocks of code attempt to set up 53307ef01d19Sgjelinek * temporary pools as well as persistent pools. In 53317ef01d19Sgjelinek * both cases we call the functions unconditionally. 53327ef01d19Sgjelinek * Within each funtion the code will check if the zone 53337ef01d19Sgjelinek * is actually configured for a temporary pool or 53347ef01d19Sgjelinek * persistent pool and just return if there is nothing 53357ef01d19Sgjelinek * to do. 53360209230bSgjelinek */ 53377ef01d19Sgjelinek if ((err = zonecfg_bind_tmp_pool(handle, zoneid, 53387ef01d19Sgjelinek pool_err, sizeof (pool_err))) != Z_OK) { 53397ef01d19Sgjelinek if (err == Z_POOL || err == Z_POOL_CREATE || 53407ef01d19Sgjelinek err == Z_POOL_BIND) 53417ef01d19Sgjelinek zerror("%s: %s", zonecfg_strerror(err), 53427ef01d19Sgjelinek pool_err); 53430209230bSgjelinek else 53447ef01d19Sgjelinek zerror(gettext("could not bind zone to " 53457ef01d19Sgjelinek "temporary pool: %s"), 53467ef01d19Sgjelinek zonecfg_strerror(err)); 53470209230bSgjelinek res = Z_ERR; 53480209230bSgjelinek } 53490209230bSgjelinek 53500209230bSgjelinek if ((err = zonecfg_bind_pool(handle, zoneid, pool_err, 53510209230bSgjelinek sizeof (pool_err))) != Z_OK) { 53520209230bSgjelinek if (err == Z_POOL || err == Z_POOL_BIND) 53537ef01d19Sgjelinek zerror("%s: %s", zonecfg_strerror(err), 53547ef01d19Sgjelinek pool_err); 53550209230bSgjelinek else 53560209230bSgjelinek zerror("%s", zonecfg_strerror(err)); 53570209230bSgjelinek } 53587ef01d19Sgjelinek } 53597ef01d19Sgjelinek } 53600209230bSgjelinek 53610209230bSgjelinek /* 53620209230bSgjelinek * If a memory cap is configured, set the cap in the kernel using 53630209230bSgjelinek * zone_setattr() and make sure the rcapd SMF service is enabled. 53640209230bSgjelinek */ 53650209230bSgjelinek if (zonecfg_getmcapent(handle, &mcap) == Z_OK) { 53660209230bSgjelinek uint64_t num; 53670209230bSgjelinek char smf_err[128]; 53680209230bSgjelinek 53690209230bSgjelinek num = (uint64_t)strtoll(mcap.zone_physmem_cap, NULL, 10); 53700209230bSgjelinek if (zone_setattr(zoneid, ZONE_ATTR_PHYS_MCAP, &num, 0) == -1) { 53710209230bSgjelinek zerror(gettext("could not set zone memory cap")); 53720209230bSgjelinek res = Z_ERR; 53730209230bSgjelinek } 53740209230bSgjelinek 53750209230bSgjelinek if (zonecfg_enable_rcapd(smf_err, sizeof (smf_err)) != Z_OK) { 53760209230bSgjelinek zerror(gettext("enabling system/rcap service failed: " 53770209230bSgjelinek "%s"), smf_err); 53780209230bSgjelinek res = Z_ERR; 53790209230bSgjelinek } 53800209230bSgjelinek } 53810209230bSgjelinek 53820209230bSgjelinek zonecfg_fini_handle(handle); 53830209230bSgjelinek 53840209230bSgjelinek return (res); 53850209230bSgjelinek } 53860209230bSgjelinek 5387fbbfbc6eSjv227347 /* 5388fbbfbc6eSjv227347 * This is an undocumented interface that is invoked by the zones SMF service 5389fbbfbc6eSjv227347 * for installed zones that won't automatically boot. 5390fbbfbc6eSjv227347 */ 5391fbbfbc6eSjv227347 /* ARGSUSED */ 5392fbbfbc6eSjv227347 static int 5393fbbfbc6eSjv227347 sysboot_func(int argc, char *argv[]) 5394fbbfbc6eSjv227347 { 5395fbbfbc6eSjv227347 int err; 5396fbbfbc6eSjv227347 zone_dochandle_t zone_handle; 5397fbbfbc6eSjv227347 brand_handle_t brand_handle; 5398fbbfbc6eSjv227347 char cmdbuf[MAXPATHLEN]; 5399fbbfbc6eSjv227347 char zonepath[MAXPATHLEN]; 5400fbbfbc6eSjv227347 5401fbbfbc6eSjv227347 /* 5402fbbfbc6eSjv227347 * This subcommand can only be executed in the global zone on non-global 5403fbbfbc6eSjv227347 * zones. 5404fbbfbc6eSjv227347 */ 5405fbbfbc6eSjv227347 if (zonecfg_in_alt_root()) 5406fbbfbc6eSjv227347 return (usage(B_FALSE)); 5407fbbfbc6eSjv227347 if (sanity_check(target_zone, CMD_SYSBOOT, B_FALSE, B_TRUE, B_FALSE) != 5408fbbfbc6eSjv227347 Z_OK) 5409fbbfbc6eSjv227347 return (Z_ERR); 5410fbbfbc6eSjv227347 5411fbbfbc6eSjv227347 /* 5412fbbfbc6eSjv227347 * Fetch the sysboot hook from the target zone's brand. 5413fbbfbc6eSjv227347 */ 5414fbbfbc6eSjv227347 if ((zone_handle = zonecfg_init_handle()) == NULL) { 5415fbbfbc6eSjv227347 zperror(cmd_to_str(CMD_SYSBOOT), B_TRUE); 5416fbbfbc6eSjv227347 return (Z_ERR); 5417fbbfbc6eSjv227347 } 5418fbbfbc6eSjv227347 if ((err = zonecfg_get_handle(target_zone, zone_handle)) != Z_OK) { 5419fbbfbc6eSjv227347 errno = err; 5420fbbfbc6eSjv227347 zperror(cmd_to_str(CMD_SYSBOOT), B_TRUE); 5421fbbfbc6eSjv227347 zonecfg_fini_handle(zone_handle); 5422fbbfbc6eSjv227347 return (Z_ERR); 5423fbbfbc6eSjv227347 } 5424fbbfbc6eSjv227347 if ((err = zonecfg_get_zonepath(zone_handle, zonepath, 5425fbbfbc6eSjv227347 sizeof (zonepath))) != Z_OK) { 5426fbbfbc6eSjv227347 errno = err; 5427fbbfbc6eSjv227347 zperror(cmd_to_str(CMD_SYSBOOT), B_TRUE); 5428fbbfbc6eSjv227347 zonecfg_fini_handle(zone_handle); 5429fbbfbc6eSjv227347 return (Z_ERR); 5430fbbfbc6eSjv227347 } 5431fbbfbc6eSjv227347 if ((brand_handle = brand_open(target_brand)) == NULL) { 5432fbbfbc6eSjv227347 zerror(gettext("missing or invalid brand during %s operation: " 5433fbbfbc6eSjv227347 "%s"), cmd_to_str(CMD_SYSBOOT), target_brand); 5434fbbfbc6eSjv227347 zonecfg_fini_handle(zone_handle); 5435fbbfbc6eSjv227347 return (Z_ERR); 5436fbbfbc6eSjv227347 } 5437fbbfbc6eSjv227347 err = get_hook(brand_handle, cmdbuf, sizeof (cmdbuf), brand_get_sysboot, 5438fbbfbc6eSjv227347 target_zone, zonepath); 5439fbbfbc6eSjv227347 brand_close(brand_handle); 5440fbbfbc6eSjv227347 zonecfg_fini_handle(zone_handle); 5441fbbfbc6eSjv227347 if (err != Z_OK) { 5442fbbfbc6eSjv227347 zerror(gettext("unable to get brand hook from brand %s for %s " 5443fbbfbc6eSjv227347 "operation"), target_brand, cmd_to_str(CMD_SYSBOOT)); 5444fbbfbc6eSjv227347 return (Z_ERR); 5445fbbfbc6eSjv227347 } 5446fbbfbc6eSjv227347 5447fbbfbc6eSjv227347 /* 5448fbbfbc6eSjv227347 * If the hook wasn't defined (which is OK), then indicate success and 5449fbbfbc6eSjv227347 * return. Otherwise, execute the hook. 5450fbbfbc6eSjv227347 */ 5451fbbfbc6eSjv227347 if (cmdbuf[0] != '\0') 5452fbbfbc6eSjv227347 return ((subproc_status(gettext("brand sysboot operation"), 5453fbbfbc6eSjv227347 do_subproc(cmdbuf), B_FALSE) == ZONE_SUBPROC_OK) ? Z_OK : 5454fbbfbc6eSjv227347 Z_BRAND_ERROR); 5455fbbfbc6eSjv227347 return (Z_OK); 5456fbbfbc6eSjv227347 } 5457fbbfbc6eSjv227347 5458555afedfScarlsonj static int 54597c478bd9Sstevel@tonic-gate help_func(int argc, char *argv[]) 54607c478bd9Sstevel@tonic-gate { 54617c478bd9Sstevel@tonic-gate int arg, cmd_num; 54627c478bd9Sstevel@tonic-gate 54637c478bd9Sstevel@tonic-gate if (argc == 0) { 54647c478bd9Sstevel@tonic-gate (void) usage(B_TRUE); 54657c478bd9Sstevel@tonic-gate return (Z_OK); 54667c478bd9Sstevel@tonic-gate } 54677c478bd9Sstevel@tonic-gate optind = 0; 54687c478bd9Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 54697c478bd9Sstevel@tonic-gate switch (arg) { 54707c478bd9Sstevel@tonic-gate case '?': 54717c478bd9Sstevel@tonic-gate sub_usage(SHELP_HELP, CMD_HELP); 54727c478bd9Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 54737c478bd9Sstevel@tonic-gate default: 54747c478bd9Sstevel@tonic-gate sub_usage(SHELP_HELP, CMD_HELP); 54757c478bd9Sstevel@tonic-gate return (Z_USAGE); 54767c478bd9Sstevel@tonic-gate } 54777c478bd9Sstevel@tonic-gate } 54787c478bd9Sstevel@tonic-gate while (optind < argc) { 5479394a25e2Scarlsonj /* Private commands have NULL short_usage; omit them */ 5480394a25e2Scarlsonj if ((cmd_num = cmd_match(argv[optind])) < 0 || 5481394a25e2Scarlsonj cmdtab[cmd_num].short_usage == NULL) { 54827c478bd9Sstevel@tonic-gate sub_usage(SHELP_HELP, CMD_HELP); 54837c478bd9Sstevel@tonic-gate return (Z_USAGE); 54847c478bd9Sstevel@tonic-gate } 54857c478bd9Sstevel@tonic-gate sub_usage(cmdtab[cmd_num].short_usage, cmd_num); 54867c478bd9Sstevel@tonic-gate optind++; 54877c478bd9Sstevel@tonic-gate } 54887c478bd9Sstevel@tonic-gate return (Z_OK); 54897c478bd9Sstevel@tonic-gate } 54907c478bd9Sstevel@tonic-gate 54917c478bd9Sstevel@tonic-gate /* 54927c478bd9Sstevel@tonic-gate * Returns: CMD_MIN thru CMD_MAX on success, -1 on error 54937c478bd9Sstevel@tonic-gate */ 54947c478bd9Sstevel@tonic-gate 54957c478bd9Sstevel@tonic-gate static int 54967c478bd9Sstevel@tonic-gate cmd_match(char *cmd) 54977c478bd9Sstevel@tonic-gate { 54987c478bd9Sstevel@tonic-gate int i; 54997c478bd9Sstevel@tonic-gate 55007c478bd9Sstevel@tonic-gate for (i = CMD_MIN; i <= CMD_MAX; i++) { 55017c478bd9Sstevel@tonic-gate /* return only if there is an exact match */ 55027c478bd9Sstevel@tonic-gate if (strcmp(cmd, cmdtab[i].cmd_name) == 0) 55037c478bd9Sstevel@tonic-gate return (cmdtab[i].cmd_num); 55047c478bd9Sstevel@tonic-gate } 55057c478bd9Sstevel@tonic-gate return (-1); 55067c478bd9Sstevel@tonic-gate } 55077c478bd9Sstevel@tonic-gate 55087c478bd9Sstevel@tonic-gate static int 55097c478bd9Sstevel@tonic-gate parse_and_run(int argc, char *argv[]) 55107c478bd9Sstevel@tonic-gate { 55117c478bd9Sstevel@tonic-gate int i = cmd_match(argv[0]); 55127c478bd9Sstevel@tonic-gate 55137c478bd9Sstevel@tonic-gate if (i < 0) 55147c478bd9Sstevel@tonic-gate return (usage(B_FALSE)); 55157c478bd9Sstevel@tonic-gate return (cmdtab[i].handler(argc - 1, &(argv[1]))); 55167c478bd9Sstevel@tonic-gate } 55177c478bd9Sstevel@tonic-gate 55187c478bd9Sstevel@tonic-gate static char * 55197c478bd9Sstevel@tonic-gate get_execbasename(char *execfullname) 55207c478bd9Sstevel@tonic-gate { 55217c478bd9Sstevel@tonic-gate char *last_slash, *execbasename; 55227c478bd9Sstevel@tonic-gate 55237c478bd9Sstevel@tonic-gate /* guard against '/' at end of command invocation */ 55247c478bd9Sstevel@tonic-gate for (;;) { 55257c478bd9Sstevel@tonic-gate last_slash = strrchr(execfullname, '/'); 55267c478bd9Sstevel@tonic-gate if (last_slash == NULL) { 55277c478bd9Sstevel@tonic-gate execbasename = execfullname; 55287c478bd9Sstevel@tonic-gate break; 55297c478bd9Sstevel@tonic-gate } else { 55307c478bd9Sstevel@tonic-gate execbasename = last_slash + 1; 55317c478bd9Sstevel@tonic-gate if (*execbasename == '\0') { 55327c478bd9Sstevel@tonic-gate *last_slash = '\0'; 55337c478bd9Sstevel@tonic-gate continue; 55347c478bd9Sstevel@tonic-gate } 55357c478bd9Sstevel@tonic-gate break; 55367c478bd9Sstevel@tonic-gate } 55377c478bd9Sstevel@tonic-gate } 55387c478bd9Sstevel@tonic-gate return (execbasename); 55397c478bd9Sstevel@tonic-gate } 55407c478bd9Sstevel@tonic-gate 5541cb8a054bSGlenn Faden static char * 5542cb8a054bSGlenn Faden get_username() 5543cb8a054bSGlenn Faden { 5544cb8a054bSGlenn Faden uid_t uid; 5545cb8a054bSGlenn Faden struct passwd *nptr; 5546cb8a054bSGlenn Faden 5547cb8a054bSGlenn Faden 5548cb8a054bSGlenn Faden /* 5549cb8a054bSGlenn Faden * Authorizations are checked to restrict access based on the 5550cb8a054bSGlenn Faden * requested operation and zone name, It is assumed that the 5551cb8a054bSGlenn Faden * program is running with all privileges, but that the real 5552cb8a054bSGlenn Faden * user ID is that of the user or role on whose behalf we are 5553cb8a054bSGlenn Faden * operating. So we start by getting the username that will be 5554cb8a054bSGlenn Faden * used for subsequent authorization checks. 5555cb8a054bSGlenn Faden */ 5556cb8a054bSGlenn Faden 5557cb8a054bSGlenn Faden uid = getuid(); 5558cb8a054bSGlenn Faden if ((nptr = getpwuid(uid)) == NULL) { 5559cb8a054bSGlenn Faden zerror(gettext("could not get user name.")); 5560cb8a054bSGlenn Faden exit(Z_ERR); 5561cb8a054bSGlenn Faden } 5562cb8a054bSGlenn Faden return (nptr->pw_name); 5563cb8a054bSGlenn Faden } 5564cb8a054bSGlenn Faden 55657c478bd9Sstevel@tonic-gate int 55667c478bd9Sstevel@tonic-gate main(int argc, char **argv) 55677c478bd9Sstevel@tonic-gate { 55687c478bd9Sstevel@tonic-gate int arg; 55697c478bd9Sstevel@tonic-gate zoneid_t zid; 5570108322fbScarlsonj struct stat st; 55719acbbeafSnn35248 char *zone_lock_env; 55729acbbeafSnn35248 int err; 55737c478bd9Sstevel@tonic-gate 55747c478bd9Sstevel@tonic-gate if ((locale = setlocale(LC_ALL, "")) == NULL) 55757c478bd9Sstevel@tonic-gate locale = "C"; 55767c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 55777c478bd9Sstevel@tonic-gate setbuf(stdout, NULL); 55787c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, SIG_IGN); 55797c478bd9Sstevel@tonic-gate execname = get_execbasename(argv[0]); 5580cb8a054bSGlenn Faden username = get_username(); 55817c478bd9Sstevel@tonic-gate target_zone = NULL; 55827c478bd9Sstevel@tonic-gate if (chdir("/") != 0) { 55837c478bd9Sstevel@tonic-gate zerror(gettext("could not change directory to /.")); 55847c478bd9Sstevel@tonic-gate exit(Z_ERR); 55857c478bd9Sstevel@tonic-gate } 5586cb8a054bSGlenn Faden 5587d0e4f536SSudheer A /* 5588d0e4f536SSudheer A * Use the default system mask rather than anything that may have been 5589d0e4f536SSudheer A * set by the caller. 5590d0e4f536SSudheer A */ 5591d0e4f536SSudheer A (void) umask(CMASK); 55927c478bd9Sstevel@tonic-gate 559399653d4eSeschrock if (init_zfs() != Z_OK) 559499653d4eSeschrock exit(Z_ERR); 559599653d4eSeschrock 5596555afedfScarlsonj while ((arg = getopt(argc, argv, "?u:z:R:")) != EOF) { 55977c478bd9Sstevel@tonic-gate switch (arg) { 55987c478bd9Sstevel@tonic-gate case '?': 55997c478bd9Sstevel@tonic-gate return (usage(B_TRUE)); 5600555afedfScarlsonj case 'u': 5601555afedfScarlsonj target_uuid = optarg; 5602555afedfScarlsonj break; 56037c478bd9Sstevel@tonic-gate case 'z': 56047c478bd9Sstevel@tonic-gate target_zone = optarg; 56057c478bd9Sstevel@tonic-gate break; 5606108322fbScarlsonj case 'R': /* private option for admin/install use */ 5607108322fbScarlsonj if (*optarg != '/') { 5608108322fbScarlsonj zerror(gettext("root path must be absolute.")); 5609108322fbScarlsonj exit(Z_ERR); 5610108322fbScarlsonj } 5611108322fbScarlsonj if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { 5612108322fbScarlsonj zerror( 5613108322fbScarlsonj gettext("root path must be a directory.")); 5614108322fbScarlsonj exit(Z_ERR); 5615108322fbScarlsonj } 5616108322fbScarlsonj zonecfg_set_root(optarg); 5617108322fbScarlsonj break; 56187c478bd9Sstevel@tonic-gate default: 56197c478bd9Sstevel@tonic-gate return (usage(B_FALSE)); 56207c478bd9Sstevel@tonic-gate } 56217c478bd9Sstevel@tonic-gate } 56227c478bd9Sstevel@tonic-gate 56237c478bd9Sstevel@tonic-gate if (optind >= argc) 56247c478bd9Sstevel@tonic-gate return (usage(B_FALSE)); 5625555afedfScarlsonj 5626555afedfScarlsonj if (target_uuid != NULL && *target_uuid != '\0') { 5627555afedfScarlsonj uuid_t uuid; 5628555afedfScarlsonj static char newtarget[ZONENAME_MAX]; 5629555afedfScarlsonj 5630555afedfScarlsonj if (uuid_parse(target_uuid, uuid) == -1) { 5631555afedfScarlsonj zerror(gettext("illegal UUID value specified")); 5632555afedfScarlsonj exit(Z_ERR); 5633555afedfScarlsonj } 5634555afedfScarlsonj if (zonecfg_get_name_by_uuid(uuid, newtarget, 5635555afedfScarlsonj sizeof (newtarget)) == Z_OK) 5636555afedfScarlsonj target_zone = newtarget; 5637555afedfScarlsonj } 5638555afedfScarlsonj 56397c478bd9Sstevel@tonic-gate if (target_zone != NULL && zone_get_id(target_zone, &zid) != 0) { 56407c478bd9Sstevel@tonic-gate errno = Z_NO_ZONE; 56417c478bd9Sstevel@tonic-gate zperror(target_zone, B_TRUE); 56427c478bd9Sstevel@tonic-gate exit(Z_ERR); 56437c478bd9Sstevel@tonic-gate } 56449acbbeafSnn35248 56459acbbeafSnn35248 /* 56469acbbeafSnn35248 * See if we have inherited the right to manipulate this zone from 56479acbbeafSnn35248 * a zoneadm instance in our ancestry. If so, set zone_lock_cnt to 56489acbbeafSnn35248 * indicate it. If not, make that explicit in our environment. 56499acbbeafSnn35248 */ 5650ff17c8bfSgjelinek zonecfg_init_lock_file(target_zone, &zone_lock_env); 56519acbbeafSnn35248 5652e5816e35SEdward Pilatowicz /* Figure out what the system's default brand is */ 5653e5816e35SEdward Pilatowicz if (zonecfg_default_brand(default_brand, 5654e5816e35SEdward Pilatowicz sizeof (default_brand)) != Z_OK) { 5655e5816e35SEdward Pilatowicz zerror(gettext("unable to determine default brand")); 5656e5816e35SEdward Pilatowicz return (Z_ERR); 5657e5816e35SEdward Pilatowicz } 5658e5816e35SEdward Pilatowicz 56599acbbeafSnn35248 /* 56609acbbeafSnn35248 * If we are going to be operating on a single zone, retrieve its 56619acbbeafSnn35248 * brand type and determine whether it is native or not. 56629acbbeafSnn35248 */ 56639acbbeafSnn35248 if ((target_zone != NULL) && 56642ad45a84Sjv227347 (strcmp(target_zone, GLOBAL_ZONENAME) != 0)) { 56659acbbeafSnn35248 if (zone_get_brand(target_zone, target_brand, 56669acbbeafSnn35248 sizeof (target_brand)) != Z_OK) { 56679acbbeafSnn35248 zerror(gettext("missing or invalid brand")); 56689acbbeafSnn35248 exit(Z_ERR); 56699acbbeafSnn35248 } 567062868012SSteve Lawrence /* 567162868012SSteve Lawrence * In the alternate root environment, the only supported 567262868012SSteve Lawrence * operations are mount and unmount. In this case, just treat 567362868012SSteve Lawrence * the zone as native if it is cluster. Cluster zones can be 567462868012SSteve Lawrence * native for the purpose of LU or upgrade, and the cluster 567562868012SSteve Lawrence * brand may not exist in the miniroot (such as in net install 567662868012SSteve Lawrence * upgrade). 567762868012SSteve Lawrence */ 567862868012SSteve Lawrence if (strcmp(target_brand, CLUSTER_BRAND_NAME) == 0) { 567962868012SSteve Lawrence if (zonecfg_in_alt_root()) { 5680e5816e35SEdward Pilatowicz (void) strlcpy(target_brand, default_brand, 568162868012SSteve Lawrence sizeof (target_brand)); 568262868012SSteve Lawrence } 568362868012SSteve Lawrence } 56849acbbeafSnn35248 } 56859acbbeafSnn35248 56869acbbeafSnn35248 err = parse_and_run(argc - optind, &argv[optind]); 56879acbbeafSnn35248 56889acbbeafSnn35248 return (err); 56897c478bd9Sstevel@tonic-gate } 5690