10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22222Scomay 230Sstevel@tonic-gate /* 241300Sgjelinek * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate * Use is subject to license terms. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * zoneadm is a command interpreter for zone administration. It is all in 320Sstevel@tonic-gate * C (i.e., no lex/yacc), and all the argument passing is argc/argv based. 330Sstevel@tonic-gate * main() calls parse_and_run() which calls cmd_match(), then invokes the 340Sstevel@tonic-gate * appropriate command's handler function. The rest of the program is the 350Sstevel@tonic-gate * handler functions and their helper functions. 360Sstevel@tonic-gate * 370Sstevel@tonic-gate * Some of the helper functions are used largely to simplify I18N: reducing 380Sstevel@tonic-gate * the need for translation notes. This is particularly true of many of 390Sstevel@tonic-gate * the zerror() calls: doing e.g. zerror(gettext("%s failed"), "foo") rather 400Sstevel@tonic-gate * than zerror(gettext("foo failed")) with a translation note indicating 410Sstevel@tonic-gate * that "foo" need not be translated. 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include <stdio.h> 450Sstevel@tonic-gate #include <errno.h> 460Sstevel@tonic-gate #include <unistd.h> 470Sstevel@tonic-gate #include <signal.h> 480Sstevel@tonic-gate #include <stdarg.h> 490Sstevel@tonic-gate #include <ctype.h> 500Sstevel@tonic-gate #include <stdlib.h> 510Sstevel@tonic-gate #include <string.h> 520Sstevel@tonic-gate #include <wait.h> 530Sstevel@tonic-gate #include <zone.h> 540Sstevel@tonic-gate #include <priv.h> 550Sstevel@tonic-gate #include <locale.h> 560Sstevel@tonic-gate #include <libintl.h> 570Sstevel@tonic-gate #include <libzonecfg.h> 580Sstevel@tonic-gate #include <bsm/adt.h> 590Sstevel@tonic-gate #include <sys/utsname.h> 600Sstevel@tonic-gate #include <sys/param.h> 610Sstevel@tonic-gate #include <sys/types.h> 620Sstevel@tonic-gate #include <sys/stat.h> 630Sstevel@tonic-gate #include <sys/statvfs.h> 640Sstevel@tonic-gate #include <assert.h> 650Sstevel@tonic-gate #include <sys/sockio.h> 660Sstevel@tonic-gate #include <sys/mntent.h> 670Sstevel@tonic-gate #include <limits.h> 68789Sahrens #include <libzfs.h> 690Sstevel@tonic-gate 700Sstevel@tonic-gate #include <fcntl.h> 710Sstevel@tonic-gate #include <door.h> 720Sstevel@tonic-gate #include <macros.h> 730Sstevel@tonic-gate #include <libgen.h> 741300Sgjelinek #include <fnmatch.h> 750Sstevel@tonic-gate 760Sstevel@tonic-gate #include <pool.h> 770Sstevel@tonic-gate #include <sys/pool.h> 780Sstevel@tonic-gate 790Sstevel@tonic-gate #define MAXARGS 8 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* Reflects kernel zone entries */ 820Sstevel@tonic-gate typedef struct zone_entry { 830Sstevel@tonic-gate zoneid_t zid; 840Sstevel@tonic-gate char zname[ZONENAME_MAX]; 850Sstevel@tonic-gate char *zstate_str; 860Sstevel@tonic-gate zone_state_t zstate_num; 870Sstevel@tonic-gate char zroot[MAXPATHLEN]; 880Sstevel@tonic-gate } zone_entry_t; 890Sstevel@tonic-gate 900Sstevel@tonic-gate static zone_entry_t *zents; 910Sstevel@tonic-gate static size_t nzents; 920Sstevel@tonic-gate 930Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ 940Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 950Sstevel@tonic-gate #endif 960Sstevel@tonic-gate 970Sstevel@tonic-gate #define Z_ERR 1 980Sstevel@tonic-gate #define Z_USAGE 2 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 0755 is the default directory mode. */ 1010Sstevel@tonic-gate #define DEFAULT_DIR_MODE \ 1020Sstevel@tonic-gate (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate #define CMD_HELP 0 1050Sstevel@tonic-gate #define CMD_BOOT 1 1060Sstevel@tonic-gate #define CMD_HALT 2 1070Sstevel@tonic-gate #define CMD_READY 3 1080Sstevel@tonic-gate #define CMD_REBOOT 4 1090Sstevel@tonic-gate #define CMD_LIST 5 1100Sstevel@tonic-gate #define CMD_VERIFY 6 1110Sstevel@tonic-gate #define CMD_INSTALL 7 1120Sstevel@tonic-gate #define CMD_UNINSTALL 8 113766Scarlsonj #define CMD_MOUNT 9 114766Scarlsonj #define CMD_UNMOUNT 10 1151300Sgjelinek #define CMD_CLONE 11 1161300Sgjelinek #define CMD_MOVE 12 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate #define CMD_MIN CMD_HELP 1191300Sgjelinek #define CMD_MAX CMD_MOVE 1201300Sgjelinek 1211300Sgjelinek #define SINGLE_USER_RETRY 30 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate struct cmd { 1240Sstevel@tonic-gate uint_t cmd_num; /* command number */ 1250Sstevel@tonic-gate char *cmd_name; /* command name */ 1260Sstevel@tonic-gate char *short_usage; /* short form help */ 1270Sstevel@tonic-gate int (*handler)(int argc, char *argv[]); /* function to call */ 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate }; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate #define SHELP_HELP "help" 1320Sstevel@tonic-gate #define SHELP_BOOT "boot [-s]" 1330Sstevel@tonic-gate #define SHELP_HALT "halt" 1340Sstevel@tonic-gate #define SHELP_READY "ready" 1350Sstevel@tonic-gate #define SHELP_REBOOT "reboot" 1360Sstevel@tonic-gate #define SHELP_LIST "list [-cipv]" 1370Sstevel@tonic-gate #define SHELP_VERIFY "verify" 1380Sstevel@tonic-gate #define SHELP_INSTALL "install" 1390Sstevel@tonic-gate #define SHELP_UNINSTALL "uninstall [-F]" 1401300Sgjelinek #define SHELP_CLONE "clone [-m method] zonename" 1411300Sgjelinek #define SHELP_MOVE "move zonepath" 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate static int help_func(int argc, char *argv[]); 1440Sstevel@tonic-gate static int ready_func(int argc, char *argv[]); 1450Sstevel@tonic-gate static int boot_func(int argc, char *argv[]); 1460Sstevel@tonic-gate static int halt_func(int argc, char *argv[]); 1470Sstevel@tonic-gate static int reboot_func(int argc, char *argv[]); 1480Sstevel@tonic-gate static int list_func(int argc, char *argv[]); 1490Sstevel@tonic-gate static int verify_func(int argc, char *argv[]); 1500Sstevel@tonic-gate static int install_func(int argc, char *argv[]); 1510Sstevel@tonic-gate static int uninstall_func(int argc, char *argv[]); 152766Scarlsonj static int mount_func(int argc, char *argv[]); 153766Scarlsonj static int unmount_func(int argc, char *argv[]); 1541300Sgjelinek static int clone_func(int argc, char *argv[]); 1551300Sgjelinek static int move_func(int argc, char *argv[]); 1560Sstevel@tonic-gate static int sanity_check(char *zone, int cmd_num, boolean_t running, 1570Sstevel@tonic-gate boolean_t unsafe_when_running); 1580Sstevel@tonic-gate static int cmd_match(char *cmd); 1590Sstevel@tonic-gate static int verify_details(int); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate static struct cmd cmdtab[] = { 1620Sstevel@tonic-gate { CMD_HELP, "help", SHELP_HELP, help_func }, 1630Sstevel@tonic-gate { CMD_BOOT, "boot", SHELP_BOOT, boot_func }, 1640Sstevel@tonic-gate { CMD_HALT, "halt", SHELP_HALT, halt_func }, 1650Sstevel@tonic-gate { CMD_READY, "ready", SHELP_READY, ready_func }, 1660Sstevel@tonic-gate { CMD_REBOOT, "reboot", SHELP_REBOOT, reboot_func }, 1670Sstevel@tonic-gate { CMD_LIST, "list", SHELP_LIST, list_func }, 1680Sstevel@tonic-gate { CMD_VERIFY, "verify", SHELP_VERIFY, verify_func }, 1690Sstevel@tonic-gate { CMD_INSTALL, "install", SHELP_INSTALL, install_func }, 1700Sstevel@tonic-gate { CMD_UNINSTALL, "uninstall", SHELP_UNINSTALL, 171766Scarlsonj uninstall_func }, 1721300Sgjelinek /* mount and unmount are private commands for admin/install */ 173766Scarlsonj { CMD_MOUNT, "mount", NULL, mount_func }, 1741300Sgjelinek { CMD_UNMOUNT, "unmount", NULL, unmount_func }, 1751300Sgjelinek { CMD_CLONE, "clone", SHELP_CLONE, clone_func }, 1761300Sgjelinek { CMD_MOVE, "move", SHELP_MOVE, move_func } 1770Sstevel@tonic-gate }; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* global variables */ 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* set early in main(), never modified thereafter, used all over the place */ 1820Sstevel@tonic-gate static char *execname; 1830Sstevel@tonic-gate static char *target_zone; 1840Sstevel@tonic-gate static char *locale; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* used in do_subproc() and signal handler */ 1870Sstevel@tonic-gate static volatile boolean_t child_killed; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate static char * 1900Sstevel@tonic-gate cmd_to_str(int cmd_num) 1910Sstevel@tonic-gate { 1920Sstevel@tonic-gate assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 1930Sstevel@tonic-gate return (cmdtab[cmd_num].cmd_name); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* This is a separate function because of gettext() wrapping. */ 1970Sstevel@tonic-gate static char * 1980Sstevel@tonic-gate long_help(int cmd_num) 1990Sstevel@tonic-gate { 200222Scomay assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); 2010Sstevel@tonic-gate switch (cmd_num) { 2020Sstevel@tonic-gate case CMD_HELP: 2030Sstevel@tonic-gate return (gettext("Print usage message.")); 2040Sstevel@tonic-gate case CMD_BOOT: 2050Sstevel@tonic-gate return (gettext("Activates (boots) specified zone. " 2060Sstevel@tonic-gate "The -s flag can be used\n\tto boot the zone in " 2070Sstevel@tonic-gate "the single-user state.")); 2080Sstevel@tonic-gate case CMD_HALT: 2090Sstevel@tonic-gate return (gettext("Halts specified zone, bypassing " 2100Sstevel@tonic-gate "shutdown scripts and removing runtime\n\t" 2110Sstevel@tonic-gate "resources of the zone.")); 2120Sstevel@tonic-gate case CMD_READY: 2130Sstevel@tonic-gate return (gettext("Prepares a zone for running " 2140Sstevel@tonic-gate "applications but does not start any user\n\t" 2150Sstevel@tonic-gate "processes in the zone.")); 2160Sstevel@tonic-gate case CMD_REBOOT: 2170Sstevel@tonic-gate return (gettext("Restarts the zone (equivalent to a " 2180Sstevel@tonic-gate "halt / boot sequence).\n\tFails if the zone is " 2190Sstevel@tonic-gate "not active.")); 2200Sstevel@tonic-gate case CMD_LIST: 2210Sstevel@tonic-gate return (gettext("Lists the current zones, or a " 2220Sstevel@tonic-gate "specific zone if indicated. By default,\n\tall " 2230Sstevel@tonic-gate "running zones are listed, though this can be " 2240Sstevel@tonic-gate "expanded to all\n\tinstalled zones with the -i " 2250Sstevel@tonic-gate "option or all configured zones with the\n\t-c " 2260Sstevel@tonic-gate "option. When used with the general -z <zone> " 2270Sstevel@tonic-gate "option, lists only the\n\tspecified zone, but " 2280Sstevel@tonic-gate "lists it regardless of its state, and the -i " 2290Sstevel@tonic-gate "and -c\n\toptions are disallowed. The -v option " 2300Sstevel@tonic-gate "can be used to display verbose\n\tinformation: " 2310Sstevel@tonic-gate "zone name, id, current state, root directory and " 2320Sstevel@tonic-gate "options.\n\tThe -p option can be used to request " 2330Sstevel@tonic-gate "machine-parsable output. The -v\n\tand -p " 2340Sstevel@tonic-gate "options are mutually exclusive. If neither -v " 2350Sstevel@tonic-gate "nor -p is used,\n\tjust the zone name is " 2360Sstevel@tonic-gate "listed.")); 2370Sstevel@tonic-gate case CMD_VERIFY: 2380Sstevel@tonic-gate return (gettext("Check to make sure the configuration " 2390Sstevel@tonic-gate "can safely be instantiated\n\ton the machine: " 2400Sstevel@tonic-gate "physical network interfaces exist, etc.")); 2410Sstevel@tonic-gate case CMD_INSTALL: 2420Sstevel@tonic-gate return (gettext("Install the configuration on to the " 2430Sstevel@tonic-gate "system.")); 2440Sstevel@tonic-gate case CMD_UNINSTALL: 2450Sstevel@tonic-gate return (gettext("Uninstall the configuration from the " 2460Sstevel@tonic-gate "system. The -F flag can be used\n\tto force the " 2470Sstevel@tonic-gate "action.")); 2481300Sgjelinek case CMD_CLONE: 2491300Sgjelinek return (gettext("Clone the installation of another " 2501300Sgjelinek "zone.")); 2511300Sgjelinek case CMD_MOVE: 2521300Sgjelinek return (gettext("Move the zone to a new zonepath.")); 253766Scarlsonj default: 254766Scarlsonj return (""); 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate /* NOTREACHED */ 257222Scomay return (NULL); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * Called with explicit B_TRUE when help is explicitly requested, B_FALSE for 2620Sstevel@tonic-gate * unexpected errors. 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate static int 2660Sstevel@tonic-gate usage(boolean_t explicit) 2670Sstevel@tonic-gate { 2680Sstevel@tonic-gate int i; 2690Sstevel@tonic-gate FILE *fd = explicit ? stdout : stderr; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate (void) fprintf(fd, "%s:\t%s help\n", gettext("usage"), execname); 2720Sstevel@tonic-gate (void) fprintf(fd, "\t%s [-z <zone>] list\n", execname); 2730Sstevel@tonic-gate (void) fprintf(fd, "\t%s -z <zone> <%s>\n", execname, 2740Sstevel@tonic-gate gettext("subcommand")); 2750Sstevel@tonic-gate (void) fprintf(fd, "\n%s:\n\n", gettext("Subcommands")); 2760Sstevel@tonic-gate for (i = CMD_MIN; i <= CMD_MAX; i++) { 277766Scarlsonj if (cmdtab[i].short_usage == NULL) 278766Scarlsonj continue; 2790Sstevel@tonic-gate (void) fprintf(fd, "%s\n", cmdtab[i].short_usage); 2800Sstevel@tonic-gate if (explicit) 2810Sstevel@tonic-gate (void) fprintf(fd, "\t%s\n\n", long_help(i)); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate if (!explicit) 2840Sstevel@tonic-gate (void) fputs("\n", fd); 2850Sstevel@tonic-gate return (Z_USAGE); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate static void 2890Sstevel@tonic-gate sub_usage(char *short_usage, int cmd_num) 2900Sstevel@tonic-gate { 2910Sstevel@tonic-gate (void) fprintf(stderr, "%s:\t%s\n", gettext("usage"), short_usage); 2920Sstevel@tonic-gate (void) fprintf(stderr, "\t%s\n", long_help(cmd_num)); 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * zperror() is like perror(3c) except that this also prints the executable 2970Sstevel@tonic-gate * name at the start of the message, and takes a boolean indicating whether 2980Sstevel@tonic-gate * to call libc'c strerror() or that from libzonecfg. 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate static void 3020Sstevel@tonic-gate zperror(const char *str, boolean_t zonecfg_error) 3030Sstevel@tonic-gate { 3040Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s: %s\n", execname, str, 3050Sstevel@tonic-gate zonecfg_error ? zonecfg_strerror(errno) : strerror(errno)); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * zperror2() is very similar to zperror() above, except it also prints a 3100Sstevel@tonic-gate * supplied zone name after the executable. 3110Sstevel@tonic-gate * 3120Sstevel@tonic-gate * All current consumers of this function want libzonecfg's strerror() rather 3130Sstevel@tonic-gate * than libc's; if this ever changes, this function can be made more generic 3140Sstevel@tonic-gate * like zperror() above. 3150Sstevel@tonic-gate */ 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate static void 3180Sstevel@tonic-gate zperror2(const char *zone, const char *str) 3190Sstevel@tonic-gate { 3200Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s: %s: %s\n", execname, zone, str, 3210Sstevel@tonic-gate zonecfg_strerror(errno)); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /* PRINTFLIKE1 */ 3250Sstevel@tonic-gate static void 3260Sstevel@tonic-gate zerror(const char *fmt, ...) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate va_list alist; 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate va_start(alist, fmt); 3310Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", execname); 3320Sstevel@tonic-gate if (target_zone != NULL) 3330Sstevel@tonic-gate (void) fprintf(stderr, "zone '%s': ", target_zone); 3340Sstevel@tonic-gate (void) vfprintf(stderr, fmt, alist); 3350Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 3360Sstevel@tonic-gate va_end(alist); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate static void * 3400Sstevel@tonic-gate safe_calloc(size_t nelem, size_t elsize) 3410Sstevel@tonic-gate { 3420Sstevel@tonic-gate void *r = calloc(nelem, elsize); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if (r == NULL) { 3450Sstevel@tonic-gate zerror(gettext("failed to allocate %lu bytes: %s"), 3460Sstevel@tonic-gate (ulong_t)nelem * elsize, strerror(errno)); 3470Sstevel@tonic-gate exit(Z_ERR); 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate return (r); 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate static void 3530Sstevel@tonic-gate zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable) 3540Sstevel@tonic-gate { 3550Sstevel@tonic-gate static boolean_t firsttime = B_TRUE; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate assert(!(verbose && parsable)); 3580Sstevel@tonic-gate if (firsttime && verbose) { 3590Sstevel@tonic-gate firsttime = B_FALSE; 3600Sstevel@tonic-gate (void) printf("%*s %-16s %-14s %-30s\n", ZONEID_WIDTH, "ID", 3610Sstevel@tonic-gate "NAME", "STATUS", "PATH"); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate if (!verbose) { 3640Sstevel@tonic-gate if (!parsable) { 3650Sstevel@tonic-gate (void) printf("%s\n", zent->zname); 3660Sstevel@tonic-gate return; 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate if (zent->zid == ZONE_ID_UNDEFINED) 3690Sstevel@tonic-gate (void) printf("-"); 3700Sstevel@tonic-gate else 3710Sstevel@tonic-gate (void) printf("%lu", zent->zid); 3720Sstevel@tonic-gate (void) printf(":%s:%s:%s\n", zent->zname, zent->zstate_str, 3730Sstevel@tonic-gate zent->zroot); 3740Sstevel@tonic-gate return; 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate if (zent->zstate_str != NULL) { 3770Sstevel@tonic-gate if (zent->zid == ZONE_ID_UNDEFINED) 3780Sstevel@tonic-gate (void) printf("%*s", ZONEID_WIDTH, "-"); 3790Sstevel@tonic-gate else 3800Sstevel@tonic-gate (void) printf("%*lu", ZONEID_WIDTH, zent->zid); 3810Sstevel@tonic-gate (void) printf(" %-16s %-14s %-30s\n", zent->zname, 3820Sstevel@tonic-gate zent->zstate_str, zent->zroot); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate static int 387766Scarlsonj lookup_zone_info(const char *zone_name, zoneid_t zid, zone_entry_t *zent) 3880Sstevel@tonic-gate { 3890Sstevel@tonic-gate char root[MAXPATHLEN]; 3900Sstevel@tonic-gate int err; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate (void) strlcpy(zent->zname, zone_name, sizeof (zent->zname)); 3930Sstevel@tonic-gate (void) strlcpy(zent->zroot, "???", sizeof (zent->zroot)); 3940Sstevel@tonic-gate zent->zstate_str = "???"; 3950Sstevel@tonic-gate 396766Scarlsonj zent->zid = zid; 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate if ((err = zone_get_zonepath(zent->zname, root, sizeof (root))) != 3990Sstevel@tonic-gate Z_OK) { 4000Sstevel@tonic-gate errno = err; 4010Sstevel@tonic-gate zperror2(zent->zname, gettext("could not get zone path")); 4020Sstevel@tonic-gate return (Z_ERR); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate (void) strlcpy(zent->zroot, root, sizeof (zent->zroot)); 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate if ((err = zone_get_state(zent->zname, &zent->zstate_num)) != Z_OK) { 4070Sstevel@tonic-gate errno = err; 4080Sstevel@tonic-gate zperror2(zent->zname, gettext("could not get state")); 4090Sstevel@tonic-gate return (Z_ERR); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate zent->zstate_str = zone_state_str(zent->zstate_num); 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate return (Z_OK); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * fetch_zents() calls zone_list(2) to find out how many zones are running 4180Sstevel@tonic-gate * (which is stored in the global nzents), then calls zone_list(2) again 4190Sstevel@tonic-gate * to fetch the list of running zones (stored in the global zents). This 4200Sstevel@tonic-gate * function may be called multiple times, so if zents is already set, we 4210Sstevel@tonic-gate * return immediately to save work. 4220Sstevel@tonic-gate */ 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate static int 425766Scarlsonj fetch_zents(void) 4260Sstevel@tonic-gate { 4270Sstevel@tonic-gate zoneid_t *zids = NULL; 4280Sstevel@tonic-gate uint_t nzents_saved; 429766Scarlsonj int i, retv; 430766Scarlsonj FILE *fp; 431766Scarlsonj boolean_t inaltroot; 432766Scarlsonj zone_entry_t *zentp; 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate if (nzents > 0) 4350Sstevel@tonic-gate return (Z_OK); 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate if (zone_list(NULL, &nzents) != 0) { 4380Sstevel@tonic-gate zperror(gettext("failed to get zoneid list"), B_FALSE); 4390Sstevel@tonic-gate return (Z_ERR); 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate again: 4430Sstevel@tonic-gate if (nzents == 0) 4440Sstevel@tonic-gate return (Z_OK); 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate zids = safe_calloc(nzents, sizeof (zoneid_t)); 4470Sstevel@tonic-gate nzents_saved = nzents; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate if (zone_list(zids, &nzents) != 0) { 4500Sstevel@tonic-gate zperror(gettext("failed to get zone list"), B_FALSE); 4510Sstevel@tonic-gate free(zids); 4520Sstevel@tonic-gate return (Z_ERR); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate if (nzents != nzents_saved) { 4550Sstevel@tonic-gate /* list changed, try again */ 4560Sstevel@tonic-gate free(zids); 4570Sstevel@tonic-gate goto again; 4580Sstevel@tonic-gate } 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate zents = safe_calloc(nzents, sizeof (zone_entry_t)); 4610Sstevel@tonic-gate 462766Scarlsonj inaltroot = zonecfg_in_alt_root(); 463766Scarlsonj if (inaltroot) 464766Scarlsonj fp = zonecfg_open_scratch("", B_FALSE); 465766Scarlsonj else 466766Scarlsonj fp = NULL; 467766Scarlsonj zentp = zents; 468766Scarlsonj retv = Z_OK; 4690Sstevel@tonic-gate for (i = 0; i < nzents; i++) { 4700Sstevel@tonic-gate char name[ZONENAME_MAX]; 471766Scarlsonj char altname[ZONENAME_MAX]; 4720Sstevel@tonic-gate 473766Scarlsonj if (getzonenamebyid(zids[i], name, sizeof (name)) < 0) { 4740Sstevel@tonic-gate zperror(gettext("failed to get zone name"), B_FALSE); 475766Scarlsonj retv = Z_ERR; 476766Scarlsonj continue; 477766Scarlsonj } 478766Scarlsonj if (zonecfg_is_scratch(name)) { 479766Scarlsonj /* Ignore scratch zones by default */ 480766Scarlsonj if (!inaltroot) 481766Scarlsonj continue; 482766Scarlsonj if (fp == NULL || 483766Scarlsonj zonecfg_reverse_scratch(fp, name, altname, 484766Scarlsonj sizeof (altname), NULL, 0) == -1) { 485924Sgjelinek zerror(gettext("could not resolve scratch " 486766Scarlsonj "zone %s"), name); 487766Scarlsonj retv = Z_ERR; 488766Scarlsonj continue; 489766Scarlsonj } 490766Scarlsonj (void) strcpy(name, altname); 491766Scarlsonj } else { 492766Scarlsonj /* Ignore non-scratch when in an alternate root */ 493766Scarlsonj if (inaltroot && strcmp(name, GLOBAL_ZONENAME) != 0) 494766Scarlsonj continue; 495766Scarlsonj } 496766Scarlsonj if (lookup_zone_info(name, zids[i], zentp) != Z_OK) { 497766Scarlsonj zerror(gettext("failed to get zone data")); 498766Scarlsonj retv = Z_ERR; 499766Scarlsonj continue; 500766Scarlsonj } 501766Scarlsonj zentp++; 5020Sstevel@tonic-gate } 503766Scarlsonj nzents = zentp - zents; 504766Scarlsonj if (fp != NULL) 505766Scarlsonj zonecfg_close_scratch(fp); 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate free(zids); 508766Scarlsonj return (retv); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 511766Scarlsonj static int 5120Sstevel@tonic-gate zone_print_list(zone_state_t min_state, boolean_t verbose, boolean_t parsable) 5130Sstevel@tonic-gate { 5140Sstevel@tonic-gate int i; 5150Sstevel@tonic-gate zone_entry_t zent; 5160Sstevel@tonic-gate FILE *cookie; 5170Sstevel@tonic-gate char *name; 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate /* 5200Sstevel@tonic-gate * First get the list of running zones from the kernel and print them. 5210Sstevel@tonic-gate * If that is all we need, then return. 5220Sstevel@tonic-gate */ 523766Scarlsonj if ((i = fetch_zents()) != Z_OK) { 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * No need for error messages; fetch_zents() has already taken 5260Sstevel@tonic-gate * care of this. 5270Sstevel@tonic-gate */ 528766Scarlsonj return (i); 5290Sstevel@tonic-gate } 530766Scarlsonj for (i = 0; i < nzents; i++) 5310Sstevel@tonic-gate zone_print(&zents[i], verbose, parsable); 5320Sstevel@tonic-gate if (min_state >= ZONE_STATE_RUNNING) 533766Scarlsonj return (Z_OK); 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * Next, get the full list of zones from the configuration, skipping 5360Sstevel@tonic-gate * any we have already printed. 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate cookie = setzoneent(); 5390Sstevel@tonic-gate while ((name = getzoneent(cookie)) != NULL) { 5400Sstevel@tonic-gate for (i = 0; i < nzents; i++) { 5410Sstevel@tonic-gate if (strcmp(zents[i].zname, name) == 0) 5420Sstevel@tonic-gate break; 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate if (i < nzents) { 5450Sstevel@tonic-gate free(name); 5460Sstevel@tonic-gate continue; 5470Sstevel@tonic-gate } 548766Scarlsonj if (lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) { 5490Sstevel@tonic-gate free(name); 5500Sstevel@tonic-gate continue; 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate free(name); 5530Sstevel@tonic-gate if (zent.zstate_num >= min_state) 5540Sstevel@tonic-gate zone_print(&zent, verbose, parsable); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate endzoneent(cookie); 557766Scarlsonj return (Z_OK); 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate static zone_entry_t * 5610Sstevel@tonic-gate lookup_running_zone(char *str) 5620Sstevel@tonic-gate { 5630Sstevel@tonic-gate zoneid_t zoneid; 5640Sstevel@tonic-gate char *cp; 5650Sstevel@tonic-gate int i; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate if (fetch_zents() != Z_OK) 5680Sstevel@tonic-gate return (NULL); 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate for (i = 0; i < nzents; i++) { 5710Sstevel@tonic-gate if (strcmp(str, zents[i].zname) == 0) 5720Sstevel@tonic-gate return (&zents[i]); 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate errno = 0; 5750Sstevel@tonic-gate zoneid = strtol(str, &cp, 0); 5760Sstevel@tonic-gate if (zoneid < MIN_ZONEID || zoneid > MAX_ZONEID || 5770Sstevel@tonic-gate errno != 0 || *cp != '\0') 5780Sstevel@tonic-gate return (NULL); 5790Sstevel@tonic-gate for (i = 0; i < nzents; i++) { 5800Sstevel@tonic-gate if (zoneid == zents[i].zid) 5810Sstevel@tonic-gate return (&zents[i]); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate return (NULL); 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate /* 5870Sstevel@tonic-gate * Check a bit in a mode_t: if on is B_TRUE, that bit should be on; if 5880Sstevel@tonic-gate * B_FALSE, it should be off. Return B_TRUE if the mode is bad (incorrect). 5890Sstevel@tonic-gate */ 5900Sstevel@tonic-gate static boolean_t 5910Sstevel@tonic-gate bad_mode_bit(mode_t mode, mode_t bit, boolean_t on, char *file) 5920Sstevel@tonic-gate { 5930Sstevel@tonic-gate char *str; 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate assert(bit == S_IRUSR || bit == S_IWUSR || bit == S_IXUSR || 5960Sstevel@tonic-gate bit == S_IRGRP || bit == S_IWGRP || bit == S_IXGRP || 5970Sstevel@tonic-gate bit == S_IROTH || bit == S_IWOTH || bit == S_IXOTH); 5980Sstevel@tonic-gate /* 5990Sstevel@tonic-gate * TRANSLATION_NOTE 6000Sstevel@tonic-gate * The strings below will be used as part of a larger message, 6010Sstevel@tonic-gate * either: 6020Sstevel@tonic-gate * (file name) must be (owner|group|world) (read|writ|execut)able 6030Sstevel@tonic-gate * or 6040Sstevel@tonic-gate * (file name) must not be (owner|group|world) (read|writ|execut)able 6050Sstevel@tonic-gate */ 6060Sstevel@tonic-gate switch (bit) { 6070Sstevel@tonic-gate case S_IRUSR: 6080Sstevel@tonic-gate str = gettext("owner readable"); 6090Sstevel@tonic-gate break; 6100Sstevel@tonic-gate case S_IWUSR: 6110Sstevel@tonic-gate str = gettext("owner writable"); 6120Sstevel@tonic-gate break; 6130Sstevel@tonic-gate case S_IXUSR: 6140Sstevel@tonic-gate str = gettext("owner executable"); 6150Sstevel@tonic-gate break; 6160Sstevel@tonic-gate case S_IRGRP: 6170Sstevel@tonic-gate str = gettext("group readable"); 6180Sstevel@tonic-gate break; 6190Sstevel@tonic-gate case S_IWGRP: 6200Sstevel@tonic-gate str = gettext("group writable"); 6210Sstevel@tonic-gate break; 6220Sstevel@tonic-gate case S_IXGRP: 6230Sstevel@tonic-gate str = gettext("group executable"); 6240Sstevel@tonic-gate break; 6250Sstevel@tonic-gate case S_IROTH: 6260Sstevel@tonic-gate str = gettext("world readable"); 6270Sstevel@tonic-gate break; 6280Sstevel@tonic-gate case S_IWOTH: 6290Sstevel@tonic-gate str = gettext("world writable"); 6300Sstevel@tonic-gate break; 6310Sstevel@tonic-gate case S_IXOTH: 6320Sstevel@tonic-gate str = gettext("world executable"); 6330Sstevel@tonic-gate break; 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate if ((mode & bit) == (on ? 0 : bit)) { 6360Sstevel@tonic-gate /* 6370Sstevel@tonic-gate * TRANSLATION_NOTE 6380Sstevel@tonic-gate * The first parameter below is a file name; the second 6390Sstevel@tonic-gate * is one of the "(owner|group|world) (read|writ|execut)able" 6400Sstevel@tonic-gate * strings from above. 6410Sstevel@tonic-gate */ 6420Sstevel@tonic-gate /* 6430Sstevel@tonic-gate * The code below could be simplified but not in a way 6440Sstevel@tonic-gate * that would easily translate to non-English locales. 6450Sstevel@tonic-gate */ 6460Sstevel@tonic-gate if (on) { 6470Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s must be %s.\n"), 6480Sstevel@tonic-gate file, str); 6490Sstevel@tonic-gate } else { 6500Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s must not be %s.\n"), 6510Sstevel@tonic-gate file, str); 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate return (B_TRUE); 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate return (B_FALSE); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate /* 6590Sstevel@tonic-gate * We want to make sure that no zone has its zone path as a child node 6600Sstevel@tonic-gate * (in the directory sense) of any other. We do that by comparing this 6610Sstevel@tonic-gate * zone's path to the path of all other (non-global) zones. The comparison 6620Sstevel@tonic-gate * in each case is simple: add '/' to the end of the path, then do a 6630Sstevel@tonic-gate * strncmp() of the two paths, using the length of the shorter one. 6640Sstevel@tonic-gate */ 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate static int 6670Sstevel@tonic-gate crosscheck_zonepaths(char *path) 6680Sstevel@tonic-gate { 6690Sstevel@tonic-gate char rpath[MAXPATHLEN]; /* resolved path */ 6700Sstevel@tonic-gate char path_copy[MAXPATHLEN]; /* copy of original path */ 6710Sstevel@tonic-gate char rpath_copy[MAXPATHLEN]; /* copy of original rpath */ 6720Sstevel@tonic-gate struct zoneent *ze; 6730Sstevel@tonic-gate int res, err; 6740Sstevel@tonic-gate FILE *cookie; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate cookie = setzoneent(); 6770Sstevel@tonic-gate while ((ze = getzoneent_private(cookie)) != NULL) { 6780Sstevel@tonic-gate /* Skip zones which are not installed. */ 6790Sstevel@tonic-gate if (ze->zone_state < ZONE_STATE_INSTALLED) { 6800Sstevel@tonic-gate free(ze); 6810Sstevel@tonic-gate continue; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate /* Skip the global zone and the current target zone. */ 6840Sstevel@tonic-gate if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0 || 6850Sstevel@tonic-gate strcmp(ze->zone_name, target_zone) == 0) { 6860Sstevel@tonic-gate free(ze); 6870Sstevel@tonic-gate continue; 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate if (strlen(ze->zone_path) == 0) { 6900Sstevel@tonic-gate /* old index file without path, fall back */ 6910Sstevel@tonic-gate if ((err = zone_get_zonepath(ze->zone_name, 6920Sstevel@tonic-gate ze->zone_path, sizeof (ze->zone_path))) != Z_OK) { 6930Sstevel@tonic-gate errno = err; 6940Sstevel@tonic-gate zperror2(ze->zone_name, 6950Sstevel@tonic-gate gettext("could not get zone path")); 6960Sstevel@tonic-gate free(ze); 6970Sstevel@tonic-gate continue; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate } 700766Scarlsonj (void) snprintf(path_copy, sizeof (path_copy), "%s%s", 701766Scarlsonj zonecfg_get_root(), ze->zone_path); 702766Scarlsonj res = resolvepath(path_copy, rpath, sizeof (rpath)); 7030Sstevel@tonic-gate if (res == -1) { 7040Sstevel@tonic-gate if (errno != ENOENT) { 705766Scarlsonj zperror(path_copy, B_FALSE); 7060Sstevel@tonic-gate free(ze); 7070Sstevel@tonic-gate return (Z_ERR); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate (void) printf(gettext("WARNING: zone %s is installed, " 7100Sstevel@tonic-gate "but its %s %s does not exist.\n"), ze->zone_name, 711766Scarlsonj "zonepath", path_copy); 7120Sstevel@tonic-gate free(ze); 7130Sstevel@tonic-gate continue; 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate rpath[res] = '\0'; 7160Sstevel@tonic-gate (void) snprintf(path_copy, sizeof (path_copy), "%s/", path); 7170Sstevel@tonic-gate (void) snprintf(rpath_copy, sizeof (rpath_copy), "%s/", rpath); 7180Sstevel@tonic-gate if (strncmp(path_copy, rpath_copy, 7190Sstevel@tonic-gate min(strlen(path_copy), strlen(rpath_copy))) == 0) { 720924Sgjelinek /* 721924Sgjelinek * TRANSLATION_NOTE 722924Sgjelinek * zonepath is a literal that should not be translated. 723924Sgjelinek */ 7240Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s zonepath (%s) and " 7250Sstevel@tonic-gate "%s zonepath (%s) overlap.\n"), 7260Sstevel@tonic-gate target_zone, path, ze->zone_name, rpath); 7270Sstevel@tonic-gate free(ze); 7280Sstevel@tonic-gate return (Z_ERR); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate free(ze); 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate endzoneent(cookie); 7330Sstevel@tonic-gate return (Z_OK); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate static int 7370Sstevel@tonic-gate validate_zonepath(char *path, int cmd_num) 7380Sstevel@tonic-gate { 7390Sstevel@tonic-gate int res; /* result of last library/system call */ 7400Sstevel@tonic-gate boolean_t err = B_FALSE; /* have we run into an error? */ 7410Sstevel@tonic-gate struct stat stbuf; 7420Sstevel@tonic-gate struct statvfs vfsbuf; 7430Sstevel@tonic-gate char rpath[MAXPATHLEN]; /* resolved path */ 7440Sstevel@tonic-gate char ppath[MAXPATHLEN]; /* parent path */ 7450Sstevel@tonic-gate char rppath[MAXPATHLEN]; /* resolved parent path */ 7460Sstevel@tonic-gate char rootpath[MAXPATHLEN]; /* root path */ 7470Sstevel@tonic-gate zone_state_t state; 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate if (path[0] != '/') { 7500Sstevel@tonic-gate (void) fprintf(stderr, 7510Sstevel@tonic-gate gettext("%s is not an absolute path.\n"), path); 7520Sstevel@tonic-gate return (Z_ERR); 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate if ((res = resolvepath(path, rpath, sizeof (rpath))) == -1) { 7550Sstevel@tonic-gate if ((errno != ENOENT) || 7561300Sgjelinek (cmd_num != CMD_VERIFY && cmd_num != CMD_INSTALL && 7571300Sgjelinek cmd_num != CMD_CLONE && cmd_num != CMD_MOVE)) { 7580Sstevel@tonic-gate zperror(path, B_FALSE); 7590Sstevel@tonic-gate return (Z_ERR); 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate if (cmd_num == CMD_VERIFY) { 762924Sgjelinek /* 763924Sgjelinek * TRANSLATION_NOTE 764924Sgjelinek * zoneadm is a literal that should not be translated. 765924Sgjelinek */ 7660Sstevel@tonic-gate (void) fprintf(stderr, gettext("WARNING: %s does not " 767924Sgjelinek "exist, so it could not be verified.\nWhen " 768924Sgjelinek "'zoneadm %s' is run, '%s' will try to create\n%s, " 769924Sgjelinek "and '%s' will be tried again,\nbut the '%s' may " 770924Sgjelinek "fail if:\nthe parent directory of %s is group- or " 771924Sgjelinek "other-writable\nor\n%s overlaps with any other " 7720Sstevel@tonic-gate "installed zones.\n"), path, 7730Sstevel@tonic-gate cmd_to_str(CMD_INSTALL), cmd_to_str(CMD_INSTALL), 7740Sstevel@tonic-gate path, cmd_to_str(CMD_VERIFY), 7750Sstevel@tonic-gate cmd_to_str(CMD_VERIFY), path, path); 7760Sstevel@tonic-gate return (Z_OK); 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate /* 7790Sstevel@tonic-gate * The zonepath is supposed to be mode 700 but its 7800Sstevel@tonic-gate * parent(s) 755. So use 755 on the mkdirp() then 7810Sstevel@tonic-gate * chmod() the zonepath itself to 700. 7820Sstevel@tonic-gate */ 7830Sstevel@tonic-gate if (mkdirp(path, DEFAULT_DIR_MODE) < 0) { 7840Sstevel@tonic-gate zperror(path, B_FALSE); 7850Sstevel@tonic-gate return (Z_ERR); 7860Sstevel@tonic-gate } 7870Sstevel@tonic-gate /* 7880Sstevel@tonic-gate * If the chmod() fails, report the error, but might 7890Sstevel@tonic-gate * as well continue the verify procedure. 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate if (chmod(path, S_IRWXU) != 0) 7920Sstevel@tonic-gate zperror(path, B_FALSE); 7930Sstevel@tonic-gate /* 7940Sstevel@tonic-gate * Since the mkdir() succeeded, we should not have to 7950Sstevel@tonic-gate * worry about a subsequent ENOENT, thus this should 7960Sstevel@tonic-gate * only recurse once. 7970Sstevel@tonic-gate */ 7981300Sgjelinek return (validate_zonepath(path, cmd_num)); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate rpath[res] = '\0'; 8010Sstevel@tonic-gate if (strcmp(path, rpath) != 0) { 8020Sstevel@tonic-gate errno = Z_RESOLVED_PATH; 8030Sstevel@tonic-gate zperror(path, B_TRUE); 8040Sstevel@tonic-gate return (Z_ERR); 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate if ((res = stat(rpath, &stbuf)) != 0) { 8070Sstevel@tonic-gate zperror(rpath, B_FALSE); 8080Sstevel@tonic-gate return (Z_ERR); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate if (!S_ISDIR(stbuf.st_mode)) { 8110Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not a directory.\n"), 8120Sstevel@tonic-gate rpath); 8130Sstevel@tonic-gate return (Z_ERR); 8140Sstevel@tonic-gate } 8150Sstevel@tonic-gate if ((strcmp(stbuf.st_fstype, MNTTYPE_TMPFS) == 0) || 8160Sstevel@tonic-gate (strcmp(stbuf.st_fstype, MNTTYPE_XMEMFS) == 0)) { 8170Sstevel@tonic-gate (void) printf(gettext("WARNING: %s is on a temporary " 8180Sstevel@tonic-gate "file-system.\n"), rpath); 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate if (crosscheck_zonepaths(rpath) != Z_OK) 8210Sstevel@tonic-gate return (Z_ERR); 8220Sstevel@tonic-gate /* 8230Sstevel@tonic-gate * Try to collect and report as many minor errors as possible 8240Sstevel@tonic-gate * before returning, so the user can learn everything that needs 8250Sstevel@tonic-gate * to be fixed up front. 8260Sstevel@tonic-gate */ 8270Sstevel@tonic-gate if (stbuf.st_uid != 0) { 8280Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not owned by root.\n"), 8290Sstevel@tonic-gate rpath); 8300Sstevel@tonic-gate err = B_TRUE; 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rpath); 8330Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rpath); 8340Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rpath); 8350Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IRGRP, B_FALSE, rpath); 8360Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rpath); 8370Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IXGRP, B_FALSE, rpath); 8380Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IROTH, B_FALSE, rpath); 8390Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rpath); 8400Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IXOTH, B_FALSE, rpath); 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate (void) snprintf(ppath, sizeof (ppath), "%s/..", path); 8430Sstevel@tonic-gate if ((res = resolvepath(ppath, rppath, sizeof (rppath))) == -1) { 8440Sstevel@tonic-gate zperror(ppath, B_FALSE); 8450Sstevel@tonic-gate return (Z_ERR); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate rppath[res] = '\0'; 8480Sstevel@tonic-gate if ((res = stat(rppath, &stbuf)) != 0) { 8490Sstevel@tonic-gate zperror(rppath, B_FALSE); 8500Sstevel@tonic-gate return (Z_ERR); 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate /* theoretically impossible */ 8530Sstevel@tonic-gate if (!S_ISDIR(stbuf.st_mode)) { 8540Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not a directory.\n"), 8550Sstevel@tonic-gate rppath); 8560Sstevel@tonic-gate return (Z_ERR); 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate if (stbuf.st_uid != 0) { 8590Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is not owned by root.\n"), 8600Sstevel@tonic-gate rppath); 8610Sstevel@tonic-gate err = B_TRUE; 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IRUSR, B_TRUE, rppath); 8640Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWUSR, B_TRUE, rppath); 8650Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IXUSR, B_TRUE, rppath); 8660Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWGRP, B_FALSE, rppath); 8670Sstevel@tonic-gate err |= bad_mode_bit(stbuf.st_mode, S_IWOTH, B_FALSE, rppath); 8680Sstevel@tonic-gate if (strcmp(rpath, rppath) == 0) { 8690Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s is its own parent.\n"), 8700Sstevel@tonic-gate rppath); 8710Sstevel@tonic-gate err = B_TRUE; 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate if (statvfs(rpath, &vfsbuf) != 0) { 8750Sstevel@tonic-gate zperror(rpath, B_FALSE); 8760Sstevel@tonic-gate return (Z_ERR); 8770Sstevel@tonic-gate } 878823Sgjelinek if (strcmp(vfsbuf.f_basetype, MNTTYPE_NFS) == 0) { 879924Sgjelinek /* 880924Sgjelinek * TRANSLATION_NOTE 881924Sgjelinek * Zonepath and NFS are literals that should not be translated. 882924Sgjelinek */ 883924Sgjelinek (void) fprintf(stderr, gettext("Zonepath %s is on an NFS " 884924Sgjelinek "mounted file-system.\n" 885924Sgjelinek "\tA local file-system must be used.\n"), rpath); 886823Sgjelinek return (Z_ERR); 887823Sgjelinek } 888823Sgjelinek if (vfsbuf.f_flag & ST_NOSUID) { 889924Sgjelinek /* 890924Sgjelinek * TRANSLATION_NOTE 891924Sgjelinek * Zonepath and nosuid are literals that should not be 892924Sgjelinek * translated. 893924Sgjelinek */ 894823Sgjelinek (void) fprintf(stderr, gettext("Zonepath %s is on a nosuid " 895924Sgjelinek "file-system.\n"), rpath); 8960Sstevel@tonic-gate return (Z_ERR); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate if ((res = zone_get_state(target_zone, &state)) != Z_OK) { 9000Sstevel@tonic-gate errno = res; 9010Sstevel@tonic-gate zperror2(target_zone, gettext("could not get state")); 9020Sstevel@tonic-gate return (Z_ERR); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate /* 9050Sstevel@tonic-gate * The existence of the root path is only bad in the configured state, 9060Sstevel@tonic-gate * as it is *supposed* to be there at the installed and later states. 9070Sstevel@tonic-gate * State/command mismatches are caught earlier in verify_details(). 9080Sstevel@tonic-gate */ 9090Sstevel@tonic-gate if (state == ZONE_STATE_CONFIGURED) { 9100Sstevel@tonic-gate if (snprintf(rootpath, sizeof (rootpath), "%s/root", rpath) >= 9110Sstevel@tonic-gate sizeof (rootpath)) { 912924Sgjelinek /* 913924Sgjelinek * TRANSLATION_NOTE 914924Sgjelinek * Zonepath is a literal that should not be translated. 915924Sgjelinek */ 9160Sstevel@tonic-gate (void) fprintf(stderr, 9170Sstevel@tonic-gate gettext("Zonepath %s is too long.\n"), rpath); 9180Sstevel@tonic-gate return (Z_ERR); 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate if ((res = stat(rootpath, &stbuf)) == 0) { 9210Sstevel@tonic-gate (void) fprintf(stderr, gettext("Rootpath %s exists; " 9220Sstevel@tonic-gate "remove or move aside prior to %s.\n"), rootpath, 9230Sstevel@tonic-gate cmd_to_str(CMD_INSTALL)); 9240Sstevel@tonic-gate return (Z_ERR); 9250Sstevel@tonic-gate } 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate return (err ? Z_ERR : Z_OK); 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate static void 9320Sstevel@tonic-gate release_lock_file(int lockfd) 9330Sstevel@tonic-gate { 9340Sstevel@tonic-gate (void) close(lockfd); 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate static int 9380Sstevel@tonic-gate grab_lock_file(const char *zone_name, int *lockfd) 9390Sstevel@tonic-gate { 9400Sstevel@tonic-gate char pathbuf[PATH_MAX]; 9410Sstevel@tonic-gate struct flock flock; 9420Sstevel@tonic-gate 943766Scarlsonj if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(), 944766Scarlsonj ZONES_TMPDIR) >= sizeof (pathbuf)) { 945766Scarlsonj zerror(gettext("alternate root path is too long")); 946766Scarlsonj return (Z_ERR); 947766Scarlsonj } 948766Scarlsonj if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) { 949766Scarlsonj zerror(gettext("could not mkdir %s: %s"), pathbuf, 9500Sstevel@tonic-gate strerror(errno)); 9510Sstevel@tonic-gate return (Z_ERR); 9520Sstevel@tonic-gate } 953766Scarlsonj (void) chmod(pathbuf, S_IRWXU); 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate /* 9560Sstevel@tonic-gate * One of these lock files is created for each zone (when needed). 9570Sstevel@tonic-gate * The lock files are not cleaned up (except on system reboot), 9580Sstevel@tonic-gate * but since there is only one per zone, there is no resource 9590Sstevel@tonic-gate * starvation issue. 9600Sstevel@tonic-gate */ 961766Scarlsonj if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock", 962766Scarlsonj zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) { 963766Scarlsonj zerror(gettext("alternate root path is too long")); 964766Scarlsonj return (Z_ERR); 965766Scarlsonj } 9660Sstevel@tonic-gate if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { 9670Sstevel@tonic-gate zerror(gettext("could not open %s: %s"), pathbuf, 9680Sstevel@tonic-gate strerror(errno)); 9690Sstevel@tonic-gate return (Z_ERR); 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate /* 9720Sstevel@tonic-gate * Lock the file to synchronize with other zoneadmds 9730Sstevel@tonic-gate */ 9740Sstevel@tonic-gate flock.l_type = F_WRLCK; 9750Sstevel@tonic-gate flock.l_whence = SEEK_SET; 9760Sstevel@tonic-gate flock.l_start = (off_t)0; 9770Sstevel@tonic-gate flock.l_len = (off_t)0; 9780Sstevel@tonic-gate if (fcntl(*lockfd, F_SETLKW, &flock) < 0) { 9790Sstevel@tonic-gate zerror(gettext("unable to lock %s: %s"), pathbuf, 9800Sstevel@tonic-gate strerror(errno)); 9810Sstevel@tonic-gate release_lock_file(*lockfd); 9820Sstevel@tonic-gate return (Z_ERR); 9830Sstevel@tonic-gate } 9840Sstevel@tonic-gate return (Z_OK); 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate 987766Scarlsonj static boolean_t 9880Sstevel@tonic-gate get_doorname(const char *zone_name, char *buffer) 9890Sstevel@tonic-gate { 990766Scarlsonj return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH, 991766Scarlsonj zonecfg_get_root(), zone_name) < PATH_MAX); 9920Sstevel@tonic-gate } 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate /* 9950Sstevel@tonic-gate * system daemons are not audited. For the global zone, this occurs 9960Sstevel@tonic-gate * "naturally" since init is started with the default audit 9970Sstevel@tonic-gate * characteristics. Since zoneadmd is a system daemon and it starts 9980Sstevel@tonic-gate * init for a zone, it is necessary to clear out the audit 9990Sstevel@tonic-gate * characteristics inherited from whomever started zoneadmd. This is 10000Sstevel@tonic-gate * indicated by the audit id, which is set from the ruid parameter of 10010Sstevel@tonic-gate * adt_set_user(), below. 10020Sstevel@tonic-gate */ 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate static void 10050Sstevel@tonic-gate prepare_audit_context() 10060Sstevel@tonic-gate { 10070Sstevel@tonic-gate adt_session_data_t *ah; 10080Sstevel@tonic-gate char *failure = gettext("audit failure: %s"); 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate if (adt_start_session(&ah, NULL, 0)) { 10110Sstevel@tonic-gate zerror(failure, strerror(errno)); 10120Sstevel@tonic-gate return; 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT, 10150Sstevel@tonic-gate ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) { 10160Sstevel@tonic-gate zerror(failure, strerror(errno)); 10170Sstevel@tonic-gate (void) adt_end_session(ah); 10180Sstevel@tonic-gate return; 10190Sstevel@tonic-gate } 10200Sstevel@tonic-gate if (adt_set_proc(ah)) 10210Sstevel@tonic-gate zerror(failure, strerror(errno)); 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate (void) adt_end_session(ah); 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate static int 10270Sstevel@tonic-gate start_zoneadmd(const char *zone_name) 10280Sstevel@tonic-gate { 10290Sstevel@tonic-gate char doorpath[PATH_MAX]; 10300Sstevel@tonic-gate pid_t child_pid; 10310Sstevel@tonic-gate int error = Z_ERR; 10320Sstevel@tonic-gate int doorfd, lockfd; 10330Sstevel@tonic-gate struct door_info info; 10340Sstevel@tonic-gate 1035766Scarlsonj if (!get_doorname(zone_name, doorpath)) 1036766Scarlsonj return (Z_ERR); 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate if (grab_lock_file(zone_name, &lockfd) != Z_OK) 10390Sstevel@tonic-gate return (Z_ERR); 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate /* 10420Sstevel@tonic-gate * Now that we have the lock, re-confirm that the daemon is 10430Sstevel@tonic-gate * *not* up and working fine. If it is still down, we have a green 10440Sstevel@tonic-gate * light to start it. 10450Sstevel@tonic-gate */ 10460Sstevel@tonic-gate if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 10470Sstevel@tonic-gate if (errno != ENOENT) { 10480Sstevel@tonic-gate zperror(doorpath, B_FALSE); 10490Sstevel@tonic-gate goto out; 10500Sstevel@tonic-gate } 10510Sstevel@tonic-gate } else { 10520Sstevel@tonic-gate if (door_info(doorfd, &info) == 0 && 10530Sstevel@tonic-gate ((info.di_attributes & DOOR_REVOKED) == 0)) { 10540Sstevel@tonic-gate error = Z_OK; 10550Sstevel@tonic-gate (void) close(doorfd); 10560Sstevel@tonic-gate goto out; 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate (void) close(doorfd); 10590Sstevel@tonic-gate } 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate if ((child_pid = fork()) == -1) { 10620Sstevel@tonic-gate zperror(gettext("could not fork"), B_FALSE); 10630Sstevel@tonic-gate goto out; 10640Sstevel@tonic-gate } else if (child_pid == 0) { 1065766Scarlsonj const char *argv[6], **ap; 1066766Scarlsonj 10670Sstevel@tonic-gate /* child process */ 10680Sstevel@tonic-gate prepare_audit_context(); 10690Sstevel@tonic-gate 1070766Scarlsonj ap = argv; 1071766Scarlsonj *ap++ = "zoneadmd"; 1072766Scarlsonj *ap++ = "-z"; 1073766Scarlsonj *ap++ = zone_name; 1074766Scarlsonj if (zonecfg_in_alt_root()) { 1075766Scarlsonj *ap++ = "-R"; 1076766Scarlsonj *ap++ = zonecfg_get_root(); 1077766Scarlsonj } 1078766Scarlsonj *ap = NULL; 1079766Scarlsonj 1080766Scarlsonj (void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv); 1081924Sgjelinek /* 1082924Sgjelinek * TRANSLATION_NOTE 1083924Sgjelinek * zoneadmd is a literal that should not be translated. 1084924Sgjelinek */ 10850Sstevel@tonic-gate zperror(gettext("could not exec zoneadmd"), B_FALSE); 10860Sstevel@tonic-gate _exit(Z_ERR); 10870Sstevel@tonic-gate } else { 10880Sstevel@tonic-gate /* parent process */ 10890Sstevel@tonic-gate pid_t retval; 10900Sstevel@tonic-gate int pstatus = 0; 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate do { 10930Sstevel@tonic-gate retval = waitpid(child_pid, &pstatus, 0); 10940Sstevel@tonic-gate } while (retval != child_pid); 10950Sstevel@tonic-gate if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) && 10960Sstevel@tonic-gate WEXITSTATUS(pstatus) != 0)) { 10970Sstevel@tonic-gate zerror(gettext("could not start %s"), "zoneadmd"); 10980Sstevel@tonic-gate goto out; 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate } 11010Sstevel@tonic-gate error = Z_OK; 11020Sstevel@tonic-gate out: 11030Sstevel@tonic-gate release_lock_file(lockfd); 11040Sstevel@tonic-gate return (error); 11050Sstevel@tonic-gate } 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate static int 11080Sstevel@tonic-gate ping_zoneadmd(const char *zone_name) 11090Sstevel@tonic-gate { 11100Sstevel@tonic-gate char doorpath[PATH_MAX]; 11110Sstevel@tonic-gate int doorfd; 11120Sstevel@tonic-gate struct door_info info; 11130Sstevel@tonic-gate 1114766Scarlsonj if (!get_doorname(zone_name, doorpath)) 1115766Scarlsonj return (Z_ERR); 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 11180Sstevel@tonic-gate return (Z_ERR); 11190Sstevel@tonic-gate } 11200Sstevel@tonic-gate if (door_info(doorfd, &info) == 0 && 11210Sstevel@tonic-gate ((info.di_attributes & DOOR_REVOKED) == 0)) { 11220Sstevel@tonic-gate (void) close(doorfd); 11230Sstevel@tonic-gate return (Z_OK); 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate (void) close(doorfd); 11260Sstevel@tonic-gate return (Z_ERR); 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate static int 11300Sstevel@tonic-gate call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg) 11310Sstevel@tonic-gate { 11320Sstevel@tonic-gate char doorpath[PATH_MAX]; 11330Sstevel@tonic-gate int doorfd, result; 11340Sstevel@tonic-gate door_arg_t darg; 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate zoneid_t zoneid; 11370Sstevel@tonic-gate uint64_t uniqid = 0; 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate zone_cmd_rval_t *rvalp; 11400Sstevel@tonic-gate size_t rlen; 11410Sstevel@tonic-gate char *cp, *errbuf; 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate rlen = getpagesize(); 11440Sstevel@tonic-gate if ((rvalp = malloc(rlen)) == NULL) { 11450Sstevel@tonic-gate zerror(gettext("failed to allocate %lu bytes: %s"), rlen, 11460Sstevel@tonic-gate strerror(errno)); 11470Sstevel@tonic-gate return (-1); 11480Sstevel@tonic-gate } 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) { 11510Sstevel@tonic-gate (void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid, 11520Sstevel@tonic-gate sizeof (uniqid)); 11530Sstevel@tonic-gate } 11540Sstevel@tonic-gate arg->uniqid = uniqid; 11550Sstevel@tonic-gate (void) strlcpy(arg->locale, locale, sizeof (arg->locale)); 1156766Scarlsonj if (!get_doorname(zone_name, doorpath)) { 1157766Scarlsonj zerror(gettext("alternate root path is too long")); 1158766Scarlsonj free(rvalp); 1159766Scarlsonj return (-1); 1160766Scarlsonj } 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate /* 11630Sstevel@tonic-gate * Loop trying to start zoneadmd; if something goes seriously 11640Sstevel@tonic-gate * wrong we break out and fail. 11650Sstevel@tonic-gate */ 11660Sstevel@tonic-gate for (;;) { 11670Sstevel@tonic-gate if (start_zoneadmd(zone_name) != Z_OK) 11680Sstevel@tonic-gate break; 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 11710Sstevel@tonic-gate zperror(gettext("failed to open zone door"), B_FALSE); 11720Sstevel@tonic-gate break; 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate darg.data_ptr = (char *)arg; 11760Sstevel@tonic-gate darg.data_size = sizeof (*arg); 11770Sstevel@tonic-gate darg.desc_ptr = NULL; 11780Sstevel@tonic-gate darg.desc_num = 0; 11790Sstevel@tonic-gate darg.rbuf = (char *)rvalp; 11800Sstevel@tonic-gate darg.rsize = rlen; 11810Sstevel@tonic-gate if (door_call(doorfd, &darg) != 0) { 11820Sstevel@tonic-gate (void) close(doorfd); 11830Sstevel@tonic-gate /* 11840Sstevel@tonic-gate * We'll get EBADF if the door has been revoked. 11850Sstevel@tonic-gate */ 11860Sstevel@tonic-gate if (errno != EBADF) { 11870Sstevel@tonic-gate zperror(gettext("door_call failed"), B_FALSE); 11880Sstevel@tonic-gate break; 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate continue; /* take another lap */ 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate (void) close(doorfd); 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate if (darg.data_size == 0) { 11950Sstevel@tonic-gate /* Door server is going away; kick it again. */ 11960Sstevel@tonic-gate continue; 11970Sstevel@tonic-gate } 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate errbuf = rvalp->errbuf; 12000Sstevel@tonic-gate while (*errbuf != '\0') { 12010Sstevel@tonic-gate /* 12020Sstevel@tonic-gate * Remove any newlines since zerror() 12030Sstevel@tonic-gate * will append one automatically. 12040Sstevel@tonic-gate */ 12050Sstevel@tonic-gate cp = strchr(errbuf, '\n'); 12060Sstevel@tonic-gate if (cp != NULL) 12070Sstevel@tonic-gate *cp = '\0'; 12080Sstevel@tonic-gate zerror("%s", errbuf); 12090Sstevel@tonic-gate if (cp == NULL) 12100Sstevel@tonic-gate break; 12110Sstevel@tonic-gate errbuf = cp + 1; 12120Sstevel@tonic-gate } 12130Sstevel@tonic-gate result = rvalp->rval == 0 ? 0 : -1; 12140Sstevel@tonic-gate free(rvalp); 12150Sstevel@tonic-gate return (result); 12160Sstevel@tonic-gate } 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate free(rvalp); 12190Sstevel@tonic-gate return (-1); 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate static int 12230Sstevel@tonic-gate ready_func(int argc, char *argv[]) 12240Sstevel@tonic-gate { 12250Sstevel@tonic-gate zone_cmd_arg_t zarg; 12260Sstevel@tonic-gate int arg; 12270Sstevel@tonic-gate 1228766Scarlsonj if (zonecfg_in_alt_root()) { 1229766Scarlsonj zerror(gettext("cannot ready zone in alternate root")); 1230766Scarlsonj return (Z_ERR); 1231766Scarlsonj } 1232766Scarlsonj 12330Sstevel@tonic-gate optind = 0; 12340Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 12350Sstevel@tonic-gate switch (arg) { 12360Sstevel@tonic-gate case '?': 12370Sstevel@tonic-gate sub_usage(SHELP_READY, CMD_READY); 12380Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 12390Sstevel@tonic-gate default: 12400Sstevel@tonic-gate sub_usage(SHELP_READY, CMD_READY); 12410Sstevel@tonic-gate return (Z_USAGE); 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate } 12440Sstevel@tonic-gate if (argc > optind) { 12450Sstevel@tonic-gate sub_usage(SHELP_READY, CMD_READY); 12460Sstevel@tonic-gate return (Z_USAGE); 12470Sstevel@tonic-gate } 12480Sstevel@tonic-gate if (sanity_check(target_zone, CMD_READY, B_FALSE, B_FALSE) != Z_OK) 12490Sstevel@tonic-gate return (Z_ERR); 12500Sstevel@tonic-gate if (verify_details(CMD_READY) != Z_OK) 12510Sstevel@tonic-gate return (Z_ERR); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate zarg.cmd = Z_READY; 12540Sstevel@tonic-gate if (call_zoneadmd(target_zone, &zarg) != 0) { 12550Sstevel@tonic-gate zerror(gettext("call to %s failed"), "zoneadmd"); 12560Sstevel@tonic-gate return (Z_ERR); 12570Sstevel@tonic-gate } 12580Sstevel@tonic-gate return (Z_OK); 12590Sstevel@tonic-gate } 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate static int 12620Sstevel@tonic-gate boot_func(int argc, char *argv[]) 12630Sstevel@tonic-gate { 12640Sstevel@tonic-gate zone_cmd_arg_t zarg; 12650Sstevel@tonic-gate int arg; 12660Sstevel@tonic-gate 1267766Scarlsonj if (zonecfg_in_alt_root()) { 1268766Scarlsonj zerror(gettext("cannot boot zone in alternate root")); 1269766Scarlsonj return (Z_ERR); 1270766Scarlsonj } 1271766Scarlsonj 12720Sstevel@tonic-gate zarg.bootbuf[0] = '\0'; 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate /* 12750Sstevel@tonic-gate * At the current time, the only supported subargument to the 12760Sstevel@tonic-gate * "boot" subcommand is "-s" which specifies a single-user boot. 12770Sstevel@tonic-gate * In the future, other boot arguments should be supported 12780Sstevel@tonic-gate * including "-m" for specifying alternate smf(5) milestones. 12790Sstevel@tonic-gate */ 12800Sstevel@tonic-gate optind = 0; 12810Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?s")) != EOF) { 12820Sstevel@tonic-gate switch (arg) { 12830Sstevel@tonic-gate case '?': 12840Sstevel@tonic-gate sub_usage(SHELP_BOOT, CMD_BOOT); 12850Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 12860Sstevel@tonic-gate case 's': 12870Sstevel@tonic-gate (void) strlcpy(zarg.bootbuf, "-s", 12880Sstevel@tonic-gate sizeof (zarg.bootbuf)); 12890Sstevel@tonic-gate break; 12900Sstevel@tonic-gate default: 12910Sstevel@tonic-gate sub_usage(SHELP_BOOT, CMD_BOOT); 12920Sstevel@tonic-gate return (Z_USAGE); 12930Sstevel@tonic-gate } 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate if (argc > optind) { 12960Sstevel@tonic-gate sub_usage(SHELP_BOOT, CMD_BOOT); 12970Sstevel@tonic-gate return (Z_USAGE); 12980Sstevel@tonic-gate } 12990Sstevel@tonic-gate if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE) != Z_OK) 13000Sstevel@tonic-gate return (Z_ERR); 13010Sstevel@tonic-gate if (verify_details(CMD_BOOT) != Z_OK) 13020Sstevel@tonic-gate return (Z_ERR); 13030Sstevel@tonic-gate zarg.cmd = Z_BOOT; 13040Sstevel@tonic-gate if (call_zoneadmd(target_zone, &zarg) != 0) { 13050Sstevel@tonic-gate zerror(gettext("call to %s failed"), "zoneadmd"); 13060Sstevel@tonic-gate return (Z_ERR); 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate return (Z_OK); 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate 13110Sstevel@tonic-gate static void 13120Sstevel@tonic-gate fake_up_local_zone(zoneid_t zid, zone_entry_t *zeptr) 13130Sstevel@tonic-gate { 13140Sstevel@tonic-gate ssize_t result; 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate zeptr->zid = zid; 13170Sstevel@tonic-gate /* 13180Sstevel@tonic-gate * Since we're looking up our own (non-global) zone name, 13190Sstevel@tonic-gate * we can be assured that it will succeed. 13200Sstevel@tonic-gate */ 13210Sstevel@tonic-gate result = getzonenamebyid(zid, zeptr->zname, sizeof (zeptr->zname)); 13220Sstevel@tonic-gate assert(result >= 0); 13230Sstevel@tonic-gate (void) strlcpy(zeptr->zroot, "/", sizeof (zeptr->zroot)); 13240Sstevel@tonic-gate zeptr->zstate_str = "running"; 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate static int 13280Sstevel@tonic-gate list_func(int argc, char *argv[]) 13290Sstevel@tonic-gate { 13300Sstevel@tonic-gate zone_entry_t *zentp, zent; 1331766Scarlsonj int arg, retv; 13320Sstevel@tonic-gate boolean_t output = B_FALSE, verbose = B_FALSE, parsable = B_FALSE; 13330Sstevel@tonic-gate zone_state_t min_state = ZONE_STATE_RUNNING; 13340Sstevel@tonic-gate zoneid_t zone_id = getzoneid(); 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate if (target_zone == NULL) { 13370Sstevel@tonic-gate /* all zones: default view to running but allow override */ 13380Sstevel@tonic-gate optind = 0; 13390Sstevel@tonic-gate while ((arg = getopt(argc, argv, "?cipv")) != EOF) { 13400Sstevel@tonic-gate switch (arg) { 13410Sstevel@tonic-gate case '?': 13420Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 13430Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 13441339Sjonb /* 13451339Sjonb * The 'i' and 'c' options are not mutually 13461339Sjonb * exclusive so if 'c' is given, then min_state 13471339Sjonb * is set to 0 (ZONE_STATE_CONFIGURED) which is 13481339Sjonb * the lowest possible state. If 'i' is given, 13491339Sjonb * then min_state is set to be the lowest state 13501339Sjonb * so far. 13511339Sjonb */ 13520Sstevel@tonic-gate case 'c': 13530Sstevel@tonic-gate min_state = ZONE_STATE_CONFIGURED; 13540Sstevel@tonic-gate break; 13550Sstevel@tonic-gate case 'i': 13561339Sjonb min_state = min(ZONE_STATE_INSTALLED, 13571339Sjonb min_state); 13581339Sjonb 13590Sstevel@tonic-gate break; 13600Sstevel@tonic-gate case 'p': 13610Sstevel@tonic-gate parsable = B_TRUE; 13620Sstevel@tonic-gate break; 13630Sstevel@tonic-gate case 'v': 13640Sstevel@tonic-gate verbose = B_TRUE; 13650Sstevel@tonic-gate break; 13660Sstevel@tonic-gate default: 13670Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 13680Sstevel@tonic-gate return (Z_USAGE); 13690Sstevel@tonic-gate } 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate if (parsable && verbose) { 13720Sstevel@tonic-gate zerror(gettext("%s -p and -v are mutually exclusive."), 13730Sstevel@tonic-gate cmd_to_str(CMD_LIST)); 13740Sstevel@tonic-gate return (Z_ERR); 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate if (zone_id == GLOBAL_ZONEID) { 1377766Scarlsonj retv = zone_print_list(min_state, verbose, parsable); 13780Sstevel@tonic-gate } else { 1379766Scarlsonj retv = Z_OK; 13800Sstevel@tonic-gate fake_up_local_zone(zone_id, &zent); 13810Sstevel@tonic-gate zone_print(&zent, verbose, parsable); 13820Sstevel@tonic-gate } 1383766Scarlsonj return (retv); 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate /* 13870Sstevel@tonic-gate * Specific target zone: disallow -i/-c suboptions. 13880Sstevel@tonic-gate */ 13890Sstevel@tonic-gate optind = 0; 13900Sstevel@tonic-gate while ((arg = getopt(argc, argv, "?pv")) != EOF) { 13910Sstevel@tonic-gate switch (arg) { 13920Sstevel@tonic-gate case '?': 13930Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 13940Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 13950Sstevel@tonic-gate case 'p': 13960Sstevel@tonic-gate parsable = B_TRUE; 13970Sstevel@tonic-gate break; 13980Sstevel@tonic-gate case 'v': 13990Sstevel@tonic-gate verbose = B_TRUE; 14000Sstevel@tonic-gate break; 14010Sstevel@tonic-gate default: 14020Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 14030Sstevel@tonic-gate return (Z_USAGE); 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate } 14060Sstevel@tonic-gate if (parsable && verbose) { 14070Sstevel@tonic-gate zerror(gettext("%s -p and -v are mutually exclusive."), 14080Sstevel@tonic-gate cmd_to_str(CMD_LIST)); 14090Sstevel@tonic-gate return (Z_ERR); 14100Sstevel@tonic-gate } 14110Sstevel@tonic-gate if (argc > optind) { 14120Sstevel@tonic-gate sub_usage(SHELP_LIST, CMD_LIST); 14130Sstevel@tonic-gate return (Z_USAGE); 14140Sstevel@tonic-gate } 14150Sstevel@tonic-gate if (zone_id != GLOBAL_ZONEID) { 14160Sstevel@tonic-gate fake_up_local_zone(zone_id, &zent); 14170Sstevel@tonic-gate /* 14180Sstevel@tonic-gate * main() will issue a Z_NO_ZONE error if it cannot get an 14190Sstevel@tonic-gate * id for target_zone, which in a non-global zone should 14200Sstevel@tonic-gate * happen for any zone name except `zonename`. Thus we 14210Sstevel@tonic-gate * assert() that here but don't otherwise check. 14220Sstevel@tonic-gate */ 14230Sstevel@tonic-gate assert(strcmp(zent.zname, target_zone) == 0); 14240Sstevel@tonic-gate zone_print(&zent, verbose, parsable); 14250Sstevel@tonic-gate output = B_TRUE; 14260Sstevel@tonic-gate } else if ((zentp = lookup_running_zone(target_zone)) != NULL) { 14270Sstevel@tonic-gate zone_print(zentp, verbose, parsable); 14280Sstevel@tonic-gate output = B_TRUE; 1429766Scarlsonj } else if (lookup_zone_info(target_zone, ZONE_ID_UNDEFINED, 1430766Scarlsonj &zent) == Z_OK) { 14310Sstevel@tonic-gate zone_print(&zent, verbose, parsable); 14320Sstevel@tonic-gate output = B_TRUE; 14330Sstevel@tonic-gate } 14340Sstevel@tonic-gate return (output ? Z_OK : Z_ERR); 14350Sstevel@tonic-gate } 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate static void 14380Sstevel@tonic-gate sigterm(int sig) 14390Sstevel@tonic-gate { 14400Sstevel@tonic-gate /* 14410Sstevel@tonic-gate * Ignore SIG{INT,TERM}, so we don't end up in an infinite loop, 14420Sstevel@tonic-gate * then propagate the signal to our process group. 14430Sstevel@tonic-gate */ 14440Sstevel@tonic-gate (void) sigset(SIGINT, SIG_IGN); 14450Sstevel@tonic-gate (void) sigset(SIGTERM, SIG_IGN); 14460Sstevel@tonic-gate (void) kill(0, sig); 14470Sstevel@tonic-gate child_killed = B_TRUE; 14480Sstevel@tonic-gate } 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate static int 14510Sstevel@tonic-gate do_subproc(char *cmdbuf) 14520Sstevel@tonic-gate { 14530Sstevel@tonic-gate char inbuf[1024]; /* arbitrary large amount */ 14540Sstevel@tonic-gate FILE *file; 14550Sstevel@tonic-gate 14560Sstevel@tonic-gate child_killed = B_FALSE; 14570Sstevel@tonic-gate /* 14580Sstevel@tonic-gate * We use popen(3c) to launch child processes for [un]install; 14590Sstevel@tonic-gate * this library call does not return a PID, so we have to kill 14600Sstevel@tonic-gate * the whole process group. To avoid killing our parent, we 14610Sstevel@tonic-gate * become a process group leader here. But doing so can wreak 14620Sstevel@tonic-gate * havoc with reading from stdin when launched by a non-job-control 14630Sstevel@tonic-gate * shell, so we close stdin and reopen it as /dev/null first. 14640Sstevel@tonic-gate */ 14650Sstevel@tonic-gate (void) close(STDIN_FILENO); 14660Sstevel@tonic-gate (void) open("/dev/null", O_RDONLY); 14670Sstevel@tonic-gate (void) setpgid(0, 0); 14680Sstevel@tonic-gate (void) sigset(SIGINT, sigterm); 14690Sstevel@tonic-gate (void) sigset(SIGTERM, sigterm); 14700Sstevel@tonic-gate file = popen(cmdbuf, "r"); 14710Sstevel@tonic-gate for (;;) { 14720Sstevel@tonic-gate if (child_killed || fgets(inbuf, sizeof (inbuf), file) == NULL) 14730Sstevel@tonic-gate break; 14740Sstevel@tonic-gate (void) fputs(inbuf, stdout); 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate (void) sigset(SIGINT, SIG_DFL); 14770Sstevel@tonic-gate (void) sigset(SIGTERM, SIG_DFL); 14780Sstevel@tonic-gate return (pclose(file)); 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate static int 14820Sstevel@tonic-gate subproc_status(const char *cmd, int status) 14830Sstevel@tonic-gate { 14840Sstevel@tonic-gate if (WIFEXITED(status)) { 14850Sstevel@tonic-gate int exit_code = WEXITSTATUS(status); 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate if (exit_code == 0) 14880Sstevel@tonic-gate return (Z_OK); 14890Sstevel@tonic-gate zerror(gettext("'%s' failed with exit code %d."), cmd, 14900Sstevel@tonic-gate exit_code); 14910Sstevel@tonic-gate } else if (WIFSIGNALED(status)) { 14920Sstevel@tonic-gate int signal = WTERMSIG(status); 14930Sstevel@tonic-gate char sigstr[SIG2STR_MAX]; 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate if (sig2str(signal, sigstr) == 0) { 14960Sstevel@tonic-gate zerror(gettext("'%s' terminated by signal SIG%s."), cmd, 14970Sstevel@tonic-gate sigstr); 14980Sstevel@tonic-gate } else { 14990Sstevel@tonic-gate zerror(gettext("'%s' terminated by an unknown signal."), 15000Sstevel@tonic-gate cmd); 15010Sstevel@tonic-gate } 15020Sstevel@tonic-gate } else { 15030Sstevel@tonic-gate zerror(gettext("'%s' failed for unknown reasons."), cmd); 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate return (Z_ERR); 15060Sstevel@tonic-gate } 15070Sstevel@tonic-gate 15080Sstevel@tonic-gate /* 15090Sstevel@tonic-gate * Various sanity checks; make sure: 15100Sstevel@tonic-gate * 1. We're in the global zone. 15110Sstevel@tonic-gate * 2. The calling user has sufficient privilege. 15120Sstevel@tonic-gate * 3. The target zone is neither the global zone nor anything starting with 15130Sstevel@tonic-gate * "SUNW". 15140Sstevel@tonic-gate * 4a. If we're looking for a 'not running' (i.e., configured or installed) 15150Sstevel@tonic-gate * zone, the name service knows about it. 15160Sstevel@tonic-gate * 4b. For some operations which expect a zone not to be running, that it is 15170Sstevel@tonic-gate * not already running (or ready). 15180Sstevel@tonic-gate */ 15190Sstevel@tonic-gate static int 15200Sstevel@tonic-gate sanity_check(char *zone, int cmd_num, boolean_t running, 15210Sstevel@tonic-gate boolean_t unsafe_when_running) 15220Sstevel@tonic-gate { 15230Sstevel@tonic-gate zone_entry_t *zent; 15240Sstevel@tonic-gate priv_set_t *privset; 15250Sstevel@tonic-gate zone_state_t state; 1526766Scarlsonj char kernzone[ZONENAME_MAX]; 1527766Scarlsonj FILE *fp; 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID) { 15300Sstevel@tonic-gate zerror(gettext("must be in the global zone to %s a zone."), 15310Sstevel@tonic-gate cmd_to_str(cmd_num)); 15320Sstevel@tonic-gate return (Z_ERR); 15330Sstevel@tonic-gate } 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate if ((privset = priv_allocset()) == NULL) { 15360Sstevel@tonic-gate zerror(gettext("%s failed"), "priv_allocset"); 15370Sstevel@tonic-gate return (Z_ERR); 15380Sstevel@tonic-gate } 15390Sstevel@tonic-gate 15400Sstevel@tonic-gate if (getppriv(PRIV_EFFECTIVE, privset) != 0) { 15410Sstevel@tonic-gate zerror(gettext("%s failed"), "getppriv"); 15420Sstevel@tonic-gate priv_freeset(privset); 15430Sstevel@tonic-gate return (Z_ERR); 15440Sstevel@tonic-gate } 15450Sstevel@tonic-gate 15460Sstevel@tonic-gate if (priv_isfullset(privset) == B_FALSE) { 15470Sstevel@tonic-gate zerror(gettext("only a privileged user may %s a zone."), 15480Sstevel@tonic-gate cmd_to_str(cmd_num)); 15490Sstevel@tonic-gate priv_freeset(privset); 15500Sstevel@tonic-gate return (Z_ERR); 15510Sstevel@tonic-gate } 15520Sstevel@tonic-gate priv_freeset(privset); 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate if (zone == NULL) { 15550Sstevel@tonic-gate zerror(gettext("no zone specified")); 15560Sstevel@tonic-gate return (Z_ERR); 15570Sstevel@tonic-gate } 15580Sstevel@tonic-gate 15590Sstevel@tonic-gate if (strcmp(zone, GLOBAL_ZONENAME) == 0) { 15600Sstevel@tonic-gate zerror(gettext("%s operation is invalid for the global zone."), 15610Sstevel@tonic-gate cmd_to_str(cmd_num)); 15620Sstevel@tonic-gate return (Z_ERR); 15630Sstevel@tonic-gate } 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate if (strncmp(zone, "SUNW", 4) == 0) { 15660Sstevel@tonic-gate zerror(gettext("%s operation is invalid for zones starting " 15670Sstevel@tonic-gate "with SUNW."), cmd_to_str(cmd_num)); 15680Sstevel@tonic-gate return (Z_ERR); 15690Sstevel@tonic-gate } 15700Sstevel@tonic-gate 1571766Scarlsonj if (!zonecfg_in_alt_root()) { 1572766Scarlsonj zent = lookup_running_zone(zone); 1573766Scarlsonj } else if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL) { 1574766Scarlsonj zent = NULL; 1575766Scarlsonj } else { 1576766Scarlsonj if (zonecfg_find_scratch(fp, zone, zonecfg_get_root(), 1577766Scarlsonj kernzone, sizeof (kernzone)) == 0) 1578766Scarlsonj zent = lookup_running_zone(kernzone); 1579766Scarlsonj else 1580766Scarlsonj zent = NULL; 1581766Scarlsonj zonecfg_close_scratch(fp); 1582766Scarlsonj } 1583766Scarlsonj 15840Sstevel@tonic-gate /* 15850Sstevel@tonic-gate * Look up from the kernel for 'running' zones. 15860Sstevel@tonic-gate */ 15870Sstevel@tonic-gate if (running) { 15880Sstevel@tonic-gate if (zent == NULL) { 15890Sstevel@tonic-gate zerror(gettext("not running")); 15900Sstevel@tonic-gate return (Z_ERR); 15910Sstevel@tonic-gate } 15920Sstevel@tonic-gate } else { 15930Sstevel@tonic-gate int err; 15940Sstevel@tonic-gate 15950Sstevel@tonic-gate if (unsafe_when_running && zent != NULL) { 15960Sstevel@tonic-gate /* check whether the zone is ready or running */ 15970Sstevel@tonic-gate if ((err = zone_get_state(zent->zname, 15980Sstevel@tonic-gate &zent->zstate_num)) != Z_OK) { 15990Sstevel@tonic-gate errno = err; 16000Sstevel@tonic-gate zperror2(zent->zname, 16010Sstevel@tonic-gate gettext("could not get state")); 16020Sstevel@tonic-gate /* can't tell, so hedge */ 16030Sstevel@tonic-gate zent->zstate_str = "ready/running"; 16040Sstevel@tonic-gate } else { 16050Sstevel@tonic-gate zent->zstate_str = 16060Sstevel@tonic-gate zone_state_str(zent->zstate_num); 16070Sstevel@tonic-gate } 16080Sstevel@tonic-gate zerror(gettext("%s operation is invalid for %s zones."), 16090Sstevel@tonic-gate cmd_to_str(cmd_num), zent->zstate_str); 16100Sstevel@tonic-gate return (Z_ERR); 16110Sstevel@tonic-gate } 16120Sstevel@tonic-gate if ((err = zone_get_state(zone, &state)) != Z_OK) { 16130Sstevel@tonic-gate errno = err; 16140Sstevel@tonic-gate zperror2(zone, gettext("could not get state")); 16150Sstevel@tonic-gate return (Z_ERR); 16160Sstevel@tonic-gate } 16170Sstevel@tonic-gate switch (cmd_num) { 16180Sstevel@tonic-gate case CMD_UNINSTALL: 16190Sstevel@tonic-gate if (state == ZONE_STATE_CONFIGURED) { 16200Sstevel@tonic-gate zerror(gettext("is already in state '%s'."), 16210Sstevel@tonic-gate zone_state_str(ZONE_STATE_CONFIGURED)); 16220Sstevel@tonic-gate return (Z_ERR); 16230Sstevel@tonic-gate } 16240Sstevel@tonic-gate break; 16251300Sgjelinek case CMD_CLONE: 16260Sstevel@tonic-gate case CMD_INSTALL: 16270Sstevel@tonic-gate if (state == ZONE_STATE_INSTALLED) { 16280Sstevel@tonic-gate zerror(gettext("is already %s."), 16290Sstevel@tonic-gate zone_state_str(ZONE_STATE_INSTALLED)); 16300Sstevel@tonic-gate return (Z_ERR); 16310Sstevel@tonic-gate } else if (state == ZONE_STATE_INCOMPLETE) { 16320Sstevel@tonic-gate zerror(gettext("zone is %s; %s required."), 16330Sstevel@tonic-gate zone_state_str(ZONE_STATE_INCOMPLETE), 16340Sstevel@tonic-gate cmd_to_str(CMD_UNINSTALL)); 16350Sstevel@tonic-gate return (Z_ERR); 16360Sstevel@tonic-gate } 16370Sstevel@tonic-gate break; 16381300Sgjelinek case CMD_MOVE: 16390Sstevel@tonic-gate case CMD_READY: 16400Sstevel@tonic-gate case CMD_BOOT: 1641766Scarlsonj case CMD_MOUNT: 16420Sstevel@tonic-gate if (state < ZONE_STATE_INSTALLED) { 16430Sstevel@tonic-gate zerror(gettext("must be %s before %s."), 16440Sstevel@tonic-gate zone_state_str(ZONE_STATE_INSTALLED), 16450Sstevel@tonic-gate cmd_to_str(cmd_num)); 16460Sstevel@tonic-gate return (Z_ERR); 16470Sstevel@tonic-gate } 16480Sstevel@tonic-gate break; 16490Sstevel@tonic-gate case CMD_VERIFY: 16500Sstevel@tonic-gate if (state == ZONE_STATE_INCOMPLETE) { 16510Sstevel@tonic-gate zerror(gettext("zone is %s; %s required."), 16520Sstevel@tonic-gate zone_state_str(ZONE_STATE_INCOMPLETE), 16530Sstevel@tonic-gate cmd_to_str(CMD_UNINSTALL)); 16540Sstevel@tonic-gate return (Z_ERR); 16550Sstevel@tonic-gate } 16560Sstevel@tonic-gate break; 1657766Scarlsonj case CMD_UNMOUNT: 1658766Scarlsonj if (state != ZONE_STATE_MOUNTED) { 1659766Scarlsonj zerror(gettext("must be %s before %s."), 1660766Scarlsonj zone_state_str(ZONE_STATE_MOUNTED), 1661766Scarlsonj cmd_to_str(cmd_num)); 1662766Scarlsonj return (Z_ERR); 1663766Scarlsonj } 1664766Scarlsonj break; 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate return (Z_OK); 16680Sstevel@tonic-gate } 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate static int 16710Sstevel@tonic-gate halt_func(int argc, char *argv[]) 16720Sstevel@tonic-gate { 16730Sstevel@tonic-gate zone_cmd_arg_t zarg; 16740Sstevel@tonic-gate int arg; 16750Sstevel@tonic-gate 1676766Scarlsonj if (zonecfg_in_alt_root()) { 1677766Scarlsonj zerror(gettext("cannot halt zone in alternate root")); 1678766Scarlsonj return (Z_ERR); 1679766Scarlsonj } 1680766Scarlsonj 16810Sstevel@tonic-gate optind = 0; 16820Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 16830Sstevel@tonic-gate switch (arg) { 16840Sstevel@tonic-gate case '?': 16850Sstevel@tonic-gate sub_usage(SHELP_HALT, CMD_HALT); 16860Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 16870Sstevel@tonic-gate default: 16880Sstevel@tonic-gate sub_usage(SHELP_HALT, CMD_HALT); 16890Sstevel@tonic-gate return (Z_USAGE); 16900Sstevel@tonic-gate } 16910Sstevel@tonic-gate } 16920Sstevel@tonic-gate if (argc > optind) { 16930Sstevel@tonic-gate sub_usage(SHELP_HALT, CMD_HALT); 16940Sstevel@tonic-gate return (Z_USAGE); 16950Sstevel@tonic-gate } 16960Sstevel@tonic-gate /* 16970Sstevel@tonic-gate * zoneadmd should be the one to decide whether or not to proceed, 16980Sstevel@tonic-gate * so even though it seems that the fourth parameter below should 16990Sstevel@tonic-gate * perhaps be B_TRUE, it really shouldn't be. 17000Sstevel@tonic-gate */ 17010Sstevel@tonic-gate if (sanity_check(target_zone, CMD_HALT, B_FALSE, B_FALSE) != Z_OK) 17020Sstevel@tonic-gate return (Z_ERR); 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate zarg.cmd = Z_HALT; 17050Sstevel@tonic-gate return ((call_zoneadmd(target_zone, &zarg) == 0) ? Z_OK : Z_ERR); 17060Sstevel@tonic-gate } 17070Sstevel@tonic-gate 17080Sstevel@tonic-gate static int 17090Sstevel@tonic-gate reboot_func(int argc, char *argv[]) 17100Sstevel@tonic-gate { 17110Sstevel@tonic-gate zone_cmd_arg_t zarg; 17120Sstevel@tonic-gate int arg; 17130Sstevel@tonic-gate 1714766Scarlsonj if (zonecfg_in_alt_root()) { 1715766Scarlsonj zerror(gettext("cannot reboot zone in alternate root")); 1716766Scarlsonj return (Z_ERR); 1717766Scarlsonj } 1718766Scarlsonj 17190Sstevel@tonic-gate optind = 0; 17200Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 17210Sstevel@tonic-gate switch (arg) { 17220Sstevel@tonic-gate case '?': 17230Sstevel@tonic-gate sub_usage(SHELP_REBOOT, CMD_REBOOT); 17240Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 17250Sstevel@tonic-gate default: 17260Sstevel@tonic-gate sub_usage(SHELP_REBOOT, CMD_REBOOT); 17270Sstevel@tonic-gate return (Z_USAGE); 17280Sstevel@tonic-gate } 17290Sstevel@tonic-gate } 17300Sstevel@tonic-gate if (argc > 0) { 17310Sstevel@tonic-gate sub_usage(SHELP_REBOOT, CMD_REBOOT); 17320Sstevel@tonic-gate return (Z_USAGE); 17330Sstevel@tonic-gate } 17340Sstevel@tonic-gate /* 17350Sstevel@tonic-gate * zoneadmd should be the one to decide whether or not to proceed, 17360Sstevel@tonic-gate * so even though it seems that the fourth parameter below should 17370Sstevel@tonic-gate * perhaps be B_TRUE, it really shouldn't be. 17380Sstevel@tonic-gate */ 17390Sstevel@tonic-gate if (sanity_check(target_zone, CMD_REBOOT, B_TRUE, B_FALSE) != Z_OK) 17400Sstevel@tonic-gate return (Z_ERR); 1741823Sgjelinek if (verify_details(CMD_REBOOT) != Z_OK) 1742823Sgjelinek return (Z_ERR); 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate zarg.cmd = Z_REBOOT; 17450Sstevel@tonic-gate return ((call_zoneadmd(target_zone, &zarg) == 0) ? Z_OK : Z_ERR); 17460Sstevel@tonic-gate } 17470Sstevel@tonic-gate 17480Sstevel@tonic-gate static int 17490Sstevel@tonic-gate verify_rctls(zone_dochandle_t handle) 17500Sstevel@tonic-gate { 17510Sstevel@tonic-gate struct zone_rctltab rctltab; 17520Sstevel@tonic-gate size_t rbs = rctlblk_size(); 17530Sstevel@tonic-gate rctlblk_t *rctlblk; 17540Sstevel@tonic-gate int error = Z_INVAL; 17550Sstevel@tonic-gate 17560Sstevel@tonic-gate if ((rctlblk = malloc(rbs)) == NULL) { 17570Sstevel@tonic-gate zerror(gettext("failed to allocate %lu bytes: %s"), rbs, 17580Sstevel@tonic-gate strerror(errno)); 17590Sstevel@tonic-gate return (Z_NOMEM); 17600Sstevel@tonic-gate } 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate if (zonecfg_setrctlent(handle) != Z_OK) { 17630Sstevel@tonic-gate zerror(gettext("zonecfg_setrctlent failed")); 17640Sstevel@tonic-gate free(rctlblk); 17650Sstevel@tonic-gate return (error); 17660Sstevel@tonic-gate } 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate rctltab.zone_rctl_valptr = NULL; 17690Sstevel@tonic-gate while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) { 17700Sstevel@tonic-gate struct zone_rctlvaltab *rctlval; 17710Sstevel@tonic-gate const char *name = rctltab.zone_rctl_name; 17720Sstevel@tonic-gate 17730Sstevel@tonic-gate if (!zonecfg_is_rctl(name)) { 17740Sstevel@tonic-gate zerror(gettext("WARNING: Ignoring unrecognized rctl " 17750Sstevel@tonic-gate "'%s'."), name); 17760Sstevel@tonic-gate zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 17770Sstevel@tonic-gate rctltab.zone_rctl_valptr = NULL; 17780Sstevel@tonic-gate continue; 17790Sstevel@tonic-gate } 17800Sstevel@tonic-gate 17810Sstevel@tonic-gate for (rctlval = rctltab.zone_rctl_valptr; rctlval != NULL; 17820Sstevel@tonic-gate rctlval = rctlval->zone_rctlval_next) { 17830Sstevel@tonic-gate if (zonecfg_construct_rctlblk(rctlval, rctlblk) 17840Sstevel@tonic-gate != Z_OK) { 17850Sstevel@tonic-gate zerror(gettext("invalid rctl value: " 17860Sstevel@tonic-gate "(priv=%s,limit=%s,action%s)"), 17870Sstevel@tonic-gate rctlval->zone_rctlval_priv, 17880Sstevel@tonic-gate rctlval->zone_rctlval_limit, 17890Sstevel@tonic-gate rctlval->zone_rctlval_action); 17900Sstevel@tonic-gate goto out; 17910Sstevel@tonic-gate } 17920Sstevel@tonic-gate if (!zonecfg_valid_rctl(name, rctlblk)) { 17930Sstevel@tonic-gate zerror(gettext("(priv=%s,limit=%s,action=%s) " 17940Sstevel@tonic-gate "is not a valid value for rctl '%s'"), 17950Sstevel@tonic-gate rctlval->zone_rctlval_priv, 17960Sstevel@tonic-gate rctlval->zone_rctlval_limit, 17970Sstevel@tonic-gate rctlval->zone_rctlval_action, 17980Sstevel@tonic-gate name); 17990Sstevel@tonic-gate goto out; 18000Sstevel@tonic-gate } 18010Sstevel@tonic-gate } 18020Sstevel@tonic-gate zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 18030Sstevel@tonic-gate } 18040Sstevel@tonic-gate rctltab.zone_rctl_valptr = NULL; 18050Sstevel@tonic-gate error = Z_OK; 18060Sstevel@tonic-gate out: 18070Sstevel@tonic-gate zonecfg_free_rctl_value_list(rctltab.zone_rctl_valptr); 18080Sstevel@tonic-gate (void) zonecfg_endrctlent(handle); 18090Sstevel@tonic-gate free(rctlblk); 18100Sstevel@tonic-gate return (error); 18110Sstevel@tonic-gate } 18120Sstevel@tonic-gate 18130Sstevel@tonic-gate static int 18140Sstevel@tonic-gate verify_pool(zone_dochandle_t handle) 18150Sstevel@tonic-gate { 18160Sstevel@tonic-gate char poolname[MAXPATHLEN]; 18170Sstevel@tonic-gate pool_conf_t *poolconf; 18180Sstevel@tonic-gate pool_t *pool; 18190Sstevel@tonic-gate int status; 18200Sstevel@tonic-gate int error; 18210Sstevel@tonic-gate 18220Sstevel@tonic-gate /* 18230Sstevel@tonic-gate * This ends up being very similar to the check done in zoneadmd. 18240Sstevel@tonic-gate */ 18250Sstevel@tonic-gate error = zonecfg_get_pool(handle, poolname, sizeof (poolname)); 18260Sstevel@tonic-gate if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) { 18270Sstevel@tonic-gate /* 18280Sstevel@tonic-gate * No pool specified. 18290Sstevel@tonic-gate */ 18300Sstevel@tonic-gate return (0); 18310Sstevel@tonic-gate } 18320Sstevel@tonic-gate if (error != Z_OK) { 18330Sstevel@tonic-gate zperror(gettext("Unable to retrieve pool name from " 18340Sstevel@tonic-gate "configuration"), B_TRUE); 18350Sstevel@tonic-gate return (error); 18360Sstevel@tonic-gate } 18370Sstevel@tonic-gate /* 18380Sstevel@tonic-gate * Don't do anything if pools aren't enabled. 18390Sstevel@tonic-gate */ 18400Sstevel@tonic-gate if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) { 18410Sstevel@tonic-gate zerror(gettext("WARNING: pools facility not active; " 18420Sstevel@tonic-gate "zone will not be bound to pool '%s'."), poolname); 18430Sstevel@tonic-gate return (Z_OK); 18440Sstevel@tonic-gate } 18450Sstevel@tonic-gate /* 18460Sstevel@tonic-gate * Try to provide a sane error message if the requested pool doesn't 18470Sstevel@tonic-gate * exist. It isn't clear that pools-related failures should 18480Sstevel@tonic-gate * necessarily translate to a failure to verify the zone configuration, 18490Sstevel@tonic-gate * hence they are not considered errors. 18500Sstevel@tonic-gate */ 18510Sstevel@tonic-gate if ((poolconf = pool_conf_alloc()) == NULL) { 18520Sstevel@tonic-gate zerror(gettext("WARNING: pool_conf_alloc failed; " 18530Sstevel@tonic-gate "using default pool")); 18540Sstevel@tonic-gate return (Z_OK); 18550Sstevel@tonic-gate } 18560Sstevel@tonic-gate if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) != 18570Sstevel@tonic-gate PO_SUCCESS) { 18580Sstevel@tonic-gate zerror(gettext("WARNING: pool_conf_open failed; " 18590Sstevel@tonic-gate "using default pool")); 18600Sstevel@tonic-gate pool_conf_free(poolconf); 18610Sstevel@tonic-gate return (Z_OK); 18620Sstevel@tonic-gate } 18630Sstevel@tonic-gate pool = pool_get_pool(poolconf, poolname); 18640Sstevel@tonic-gate (void) pool_conf_close(poolconf); 18650Sstevel@tonic-gate pool_conf_free(poolconf); 18660Sstevel@tonic-gate if (pool == NULL) { 18670Sstevel@tonic-gate zerror(gettext("WARNING: pool '%s' not found. " 18680Sstevel@tonic-gate "using default pool"), poolname); 18690Sstevel@tonic-gate } 18700Sstevel@tonic-gate 18710Sstevel@tonic-gate return (Z_OK); 18720Sstevel@tonic-gate } 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate static int 1875823Sgjelinek verify_ipd(zone_dochandle_t handle) 1876823Sgjelinek { 1877823Sgjelinek int return_code = Z_OK; 1878823Sgjelinek struct zone_fstab fstab; 1879823Sgjelinek struct stat st; 1880823Sgjelinek char specdir[MAXPATHLEN]; 1881823Sgjelinek 1882823Sgjelinek if (zonecfg_setipdent(handle) != Z_OK) { 1883924Sgjelinek /* 1884924Sgjelinek * TRANSLATION_NOTE 1885924Sgjelinek * inherit-pkg-dirs is a literal that should not be translated. 1886924Sgjelinek */ 1887924Sgjelinek (void) fprintf(stderr, gettext("could not verify " 1888823Sgjelinek "inherit-pkg-dirs: unable to enumerate mounts\n")); 1889823Sgjelinek return (Z_ERR); 1890823Sgjelinek } 1891823Sgjelinek while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 1892823Sgjelinek /* 1893823Sgjelinek * Verify fs_dir exists. 1894823Sgjelinek */ 1895823Sgjelinek (void) snprintf(specdir, sizeof (specdir), "%s%s", 1896823Sgjelinek zonecfg_get_root(), fstab.zone_fs_dir); 1897823Sgjelinek if (stat(specdir, &st) != 0) { 1898924Sgjelinek /* 1899924Sgjelinek * TRANSLATION_NOTE 1900924Sgjelinek * inherit-pkg-dir is a literal that should not be 1901924Sgjelinek * translated. 1902924Sgjelinek */ 1903924Sgjelinek (void) fprintf(stderr, gettext("could not verify " 1904823Sgjelinek "inherit-pkg-dir %s: %s\n"), 1905823Sgjelinek fstab.zone_fs_dir, strerror(errno)); 1906823Sgjelinek return_code = Z_ERR; 1907823Sgjelinek } 1908823Sgjelinek if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) { 1909924Sgjelinek /* 1910924Sgjelinek * TRANSLATION_NOTE 1911924Sgjelinek * inherit-pkg-dir and NFS are literals that should 1912924Sgjelinek * not be translated. 1913924Sgjelinek */ 1914823Sgjelinek (void) fprintf(stderr, gettext("cannot verify " 1915924Sgjelinek "inherit-pkg-dir %s: NFS mounted file-system.\n" 1916924Sgjelinek "\tA local file-system must be used.\n"), 1917823Sgjelinek fstab.zone_fs_dir); 1918823Sgjelinek return_code = Z_ERR; 1919823Sgjelinek } 1920823Sgjelinek } 1921823Sgjelinek (void) zonecfg_endipdent(handle); 1922823Sgjelinek 1923823Sgjelinek return (return_code); 1924823Sgjelinek } 1925823Sgjelinek 1926*1393Slling /* ARGSUSED */ 1927*1393Slling static void 1928*1393Slling zfs_fs_err_handler(const char *fmt, va_list ap) 1929*1393Slling { 1930*1393Slling /* 1931*1393Slling * Do nothing - do not print the libzfs error messages. 1932*1393Slling */ 1933*1393Slling } 1934*1393Slling 1935*1393Slling /* 1936*1393Slling * Verify that the ZFS dataset exists, and its mountpoint 1937*1393Slling * property is set to "legacy". 1938*1393Slling */ 1939*1393Slling static int 1940*1393Slling verify_fs_zfs(struct zone_fstab *fstab) 1941*1393Slling { 1942*1393Slling zfs_handle_t *zhp; 1943*1393Slling char propbuf[ZFS_MAXPROPLEN]; 1944*1393Slling 1945*1393Slling zfs_set_error_handler(zfs_fs_err_handler); 1946*1393Slling 1947*1393Slling if ((zhp = zfs_open(fstab->zone_fs_special, ZFS_TYPE_ANY)) == NULL) { 1948*1393Slling (void) fprintf(stderr, gettext("cannot verify fs %s: " 1949*1393Slling "could not access zfs dataset '%s'\n"), 1950*1393Slling fstab->zone_fs_dir, fstab->zone_fs_special); 1951*1393Slling return (Z_ERR); 1952*1393Slling } 1953*1393Slling 1954*1393Slling if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 1955*1393Slling (void) fprintf(stderr, gettext("cannot verify fs %s: " 1956*1393Slling "'%s' is not a filesystem\n"), 1957*1393Slling fstab->zone_fs_dir, fstab->zone_fs_special); 1958*1393Slling zfs_close(zhp); 1959*1393Slling return (Z_ERR); 1960*1393Slling } 1961*1393Slling 1962*1393Slling if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf), 1963*1393Slling NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) { 1964*1393Slling (void) fprintf(stderr, gettext("cannot verify fs %s: zfs '%s' " 1965*1393Slling "mountpoint is not \"legacy\"\n"), 1966*1393Slling fstab->zone_fs_dir, fstab->zone_fs_special); 1967*1393Slling zfs_close(zhp); 1968*1393Slling return (Z_ERR); 1969*1393Slling } 1970*1393Slling 1971*1393Slling zfs_close(zhp); 1972*1393Slling return (Z_OK); 1973*1393Slling } 1974*1393Slling 1975*1393Slling /* 1976*1393Slling * Verify that the special device/filesystem exists and is valid. 1977*1393Slling */ 1978*1393Slling static int 1979*1393Slling verify_fs_special(struct zone_fstab *fstab) 1980*1393Slling { 1981*1393Slling struct stat st; 1982*1393Slling 1983*1393Slling if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0) 1984*1393Slling return (verify_fs_zfs(fstab)); 1985*1393Slling 1986*1393Slling if (stat(fstab->zone_fs_special, &st) != 0) { 1987*1393Slling (void) fprintf(stderr, gettext("cannot verify fs " 1988*1393Slling "%s: could not access %s: %s\n"), fstab->zone_fs_dir, 1989*1393Slling fstab->zone_fs_special, strerror(errno)); 1990*1393Slling return (Z_ERR); 1991*1393Slling } 1992*1393Slling 1993*1393Slling if (strcmp(st.st_fstype, MNTTYPE_NFS) == 0) { 1994*1393Slling /* 1995*1393Slling * TRANSLATION_NOTE 1996*1393Slling * fs and NFS are literals that should 1997*1393Slling * not be translated. 1998*1393Slling */ 1999*1393Slling (void) fprintf(stderr, gettext("cannot verify " 2000*1393Slling "fs %s: NFS mounted file-system.\n" 2001*1393Slling "\tA local file-system must be used.\n"), 2002*1393Slling fstab->zone_fs_special); 2003*1393Slling return (Z_ERR); 2004*1393Slling } 2005*1393Slling 2006*1393Slling return (Z_OK); 2007*1393Slling } 2008*1393Slling 2009823Sgjelinek static int 20100Sstevel@tonic-gate verify_filesystems(zone_dochandle_t handle) 20110Sstevel@tonic-gate { 20120Sstevel@tonic-gate int return_code = Z_OK; 20130Sstevel@tonic-gate struct zone_fstab fstab; 20140Sstevel@tonic-gate char cmdbuf[MAXPATHLEN]; 20150Sstevel@tonic-gate struct stat st; 20160Sstevel@tonic-gate 20170Sstevel@tonic-gate /* 20180Sstevel@tonic-gate * No need to verify inherit-pkg-dir fs types, as their type is 20190Sstevel@tonic-gate * implicitly lofs, which is known. Therefore, the types are only 20200Sstevel@tonic-gate * verified for regular filesystems below. 20210Sstevel@tonic-gate * 20220Sstevel@tonic-gate * Since the actual mount point is not known until the dependent mounts 20230Sstevel@tonic-gate * are performed, we don't attempt any path validation here: that will 20240Sstevel@tonic-gate * happen later when zoneadmd actually does the mounts. 20250Sstevel@tonic-gate */ 20260Sstevel@tonic-gate if (zonecfg_setfsent(handle) != Z_OK) { 2027924Sgjelinek (void) fprintf(stderr, gettext("could not verify file-systems: " 20280Sstevel@tonic-gate "unable to enumerate mounts\n")); 20290Sstevel@tonic-gate return (Z_ERR); 20300Sstevel@tonic-gate } 20310Sstevel@tonic-gate while (zonecfg_getfsent(handle, &fstab) == Z_OK) { 20320Sstevel@tonic-gate if (!zonecfg_valid_fs_type(fstab.zone_fs_type)) { 20330Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot verify fs %s: " 20340Sstevel@tonic-gate "type %s is not allowed.\n"), fstab.zone_fs_dir, 20350Sstevel@tonic-gate fstab.zone_fs_type); 20360Sstevel@tonic-gate return_code = Z_ERR; 20370Sstevel@tonic-gate goto next_fs; 20380Sstevel@tonic-gate } 20390Sstevel@tonic-gate /* 20400Sstevel@tonic-gate * Verify /usr/lib/fs/<fstype>/mount exists. 20410Sstevel@tonic-gate */ 20420Sstevel@tonic-gate if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/mount", 20430Sstevel@tonic-gate fstab.zone_fs_type) > sizeof (cmdbuf)) { 20440Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot verify fs %s: " 20450Sstevel@tonic-gate "type %s is too long.\n"), fstab.zone_fs_dir, 20460Sstevel@tonic-gate fstab.zone_fs_type); 20470Sstevel@tonic-gate return_code = Z_ERR; 20480Sstevel@tonic-gate goto next_fs; 20490Sstevel@tonic-gate } 20500Sstevel@tonic-gate if (stat(cmdbuf, &st) != 0) { 2051924Sgjelinek (void) fprintf(stderr, gettext("could not verify fs " 2052924Sgjelinek "%s: could not access %s: %s\n"), fstab.zone_fs_dir, 20530Sstevel@tonic-gate cmdbuf, strerror(errno)); 20540Sstevel@tonic-gate return_code = Z_ERR; 20550Sstevel@tonic-gate goto next_fs; 20560Sstevel@tonic-gate } 20570Sstevel@tonic-gate if (!S_ISREG(st.st_mode)) { 2058924Sgjelinek (void) fprintf(stderr, gettext("could not verify fs " 2059924Sgjelinek "%s: %s is not a regular file\n"), 2060924Sgjelinek fstab.zone_fs_dir, cmdbuf); 20610Sstevel@tonic-gate return_code = Z_ERR; 20620Sstevel@tonic-gate goto next_fs; 20630Sstevel@tonic-gate } 20640Sstevel@tonic-gate /* 20650Sstevel@tonic-gate * Verify /usr/lib/fs/<fstype>/fsck exists iff zone_fs_raw is 20660Sstevel@tonic-gate * set. 20670Sstevel@tonic-gate */ 20680Sstevel@tonic-gate if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/fsck", 20690Sstevel@tonic-gate fstab.zone_fs_type) > sizeof (cmdbuf)) { 20700Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot verify fs %s: " 20710Sstevel@tonic-gate "type %s is too long.\n"), fstab.zone_fs_dir, 20720Sstevel@tonic-gate fstab.zone_fs_type); 20730Sstevel@tonic-gate return_code = Z_ERR; 20740Sstevel@tonic-gate goto next_fs; 20750Sstevel@tonic-gate } 20760Sstevel@tonic-gate if (fstab.zone_fs_raw[0] == '\0' && stat(cmdbuf, &st) == 0) { 2077924Sgjelinek (void) fprintf(stderr, gettext("could not verify fs " 2078924Sgjelinek "%s: must specify 'raw' device for %s " 2079924Sgjelinek "file-systems\n"), 20800Sstevel@tonic-gate fstab.zone_fs_dir, fstab.zone_fs_type); 20810Sstevel@tonic-gate return_code = Z_ERR; 20820Sstevel@tonic-gate goto next_fs; 20830Sstevel@tonic-gate } 20840Sstevel@tonic-gate if (fstab.zone_fs_raw[0] != '\0' && 20850Sstevel@tonic-gate (stat(cmdbuf, &st) != 0 || !S_ISREG(st.st_mode))) { 20860Sstevel@tonic-gate (void) fprintf(stderr, gettext("cannot verify fs %s: " 20870Sstevel@tonic-gate "'raw' device specified but " 20880Sstevel@tonic-gate "no fsck executable exists for %s\n"), 20890Sstevel@tonic-gate fstab.zone_fs_dir, fstab.zone_fs_type); 20900Sstevel@tonic-gate return_code = Z_ERR; 20910Sstevel@tonic-gate goto next_fs; 20920Sstevel@tonic-gate } 2093*1393Slling 2094*1393Slling /* Verify fs_special. */ 2095*1393Slling if ((return_code = verify_fs_special(&fstab)) != Z_OK) 2096823Sgjelinek goto next_fs; 2097*1393Slling 2098*1393Slling /* Verify fs_raw. */ 2099823Sgjelinek if (fstab.zone_fs_raw[0] != '\0' && 2100823Sgjelinek stat(fstab.zone_fs_raw, &st) != 0) { 2101924Sgjelinek /* 2102924Sgjelinek * TRANSLATION_NOTE 2103924Sgjelinek * fs is a literal that should not be translated. 2104924Sgjelinek */ 2105924Sgjelinek (void) fprintf(stderr, gettext("could not verify fs " 2106924Sgjelinek "%s: could not access %s: %s\n"), fstab.zone_fs_dir, 2107823Sgjelinek fstab.zone_fs_raw, strerror(errno)); 2108823Sgjelinek return_code = Z_ERR; 2109823Sgjelinek goto next_fs; 2110823Sgjelinek } 21110Sstevel@tonic-gate next_fs: 21120Sstevel@tonic-gate zonecfg_free_fs_option_list(fstab.zone_fs_options); 21130Sstevel@tonic-gate } 21140Sstevel@tonic-gate (void) zonecfg_endfsent(handle); 21150Sstevel@tonic-gate 21160Sstevel@tonic-gate return (return_code); 21170Sstevel@tonic-gate } 21180Sstevel@tonic-gate 2119789Sahrens const char *current_dataset; 2120789Sahrens 2121789Sahrens /* 2122789Sahrens * Custom error handler for errors incurred as part of the checks below. We 2123789Sahrens * want to trim off the leading 'cannot open ...' to create a better error 2124789Sahrens * message. The only other way this can fail is if we fail to set the 'zoned' 2125789Sahrens * property. In this case we just pass the error on verbatim. 2126789Sahrens */ 2127789Sahrens static void 2128789Sahrens zfs_error_handler(const char *fmt, va_list ap) 2129789Sahrens { 2130789Sahrens char buf[1024]; 2131789Sahrens 2132789Sahrens (void) vsnprintf(buf, sizeof (buf), fmt, ap); 2133789Sahrens 2134789Sahrens if (strncmp(gettext("cannot open "), buf, 2135789Sahrens strlen(gettext("cannot open "))) == 0) 2136924Sgjelinek /* 2137924Sgjelinek * TRANSLATION_NOTE 2138924Sgjelinek * zfs and dataset are literals that should not be translated. 2139924Sgjelinek */ 2140924Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 2141789Sahrens "dataset %s%s\n"), current_dataset, strchr(buf, ':')); 2142789Sahrens else 2143924Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs dataset " 2144789Sahrens "%s: %s\n"), current_dataset, buf); 2145789Sahrens } 2146789Sahrens 2147789Sahrens /* ARGSUSED */ 2148789Sahrens static int 2149789Sahrens check_zvol(zfs_handle_t *zhp, void *unused) 2150789Sahrens { 2151789Sahrens int ret; 2152789Sahrens 2153789Sahrens if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 2154924Sgjelinek /* 2155924Sgjelinek * TRANSLATION_NOTE 2156924Sgjelinek * zfs and dataset are literals that should not be translated. 2157924Sgjelinek */ 2158789Sahrens (void) fprintf(stderr, gettext("cannot verify zfs dataset %s: " 2159789Sahrens "volumes cannot be specified as a zone dataset resource\n"), 2160789Sahrens zfs_get_name(zhp)); 2161789Sahrens ret = -1; 2162789Sahrens } else { 2163789Sahrens ret = zfs_iter_children(zhp, check_zvol, NULL); 2164789Sahrens } 2165789Sahrens 2166789Sahrens zfs_close(zhp); 2167789Sahrens 2168789Sahrens return (ret); 2169789Sahrens } 2170789Sahrens 2171789Sahrens /* 2172789Sahrens * Validate that the given dataset exists on the system, and that neither it nor 2173789Sahrens * its children are zvols. 2174789Sahrens * 2175789Sahrens * Note that we don't do anything with the 'zoned' property here. All 2176789Sahrens * management is done in zoneadmd when the zone is actually rebooted. This 2177789Sahrens * allows us to automatically set the zoned property even when a zone is 2178789Sahrens * rebooted by the administrator. 2179789Sahrens */ 2180789Sahrens static int 2181789Sahrens verify_datasets(zone_dochandle_t handle) 2182789Sahrens { 2183789Sahrens int return_code = Z_OK; 2184789Sahrens struct zone_dstab dstab; 2185789Sahrens zfs_handle_t *zhp; 2186789Sahrens char propbuf[ZFS_MAXPROPLEN]; 2187789Sahrens char source[ZFS_MAXNAMELEN]; 2188789Sahrens zfs_source_t srctype; 2189789Sahrens 2190789Sahrens if (zonecfg_setdsent(handle) != Z_OK) { 2191924Sgjelinek /* 2192924Sgjelinek * TRANSLATION_NOTE 2193924Sgjelinek * zfs and dataset are literals that should not be translated. 2194924Sgjelinek */ 2195924Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs datasets: " 2196789Sahrens "unable to enumerate datasets\n")); 2197789Sahrens return (Z_ERR); 2198789Sahrens } 2199789Sahrens 2200789Sahrens zfs_set_error_handler(zfs_error_handler); 2201789Sahrens 2202789Sahrens while (zonecfg_getdsent(handle, &dstab) == Z_OK) { 2203789Sahrens 2204789Sahrens current_dataset = dstab.zone_dataset_name; 2205789Sahrens 2206789Sahrens if ((zhp = zfs_open(dstab.zone_dataset_name, 2207789Sahrens ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { 2208789Sahrens return_code = Z_ERR; 2209789Sahrens continue; 2210789Sahrens } 2211789Sahrens 2212789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, 2213789Sahrens sizeof (propbuf), &srctype, source, 2214789Sahrens sizeof (source), 0) == 0 && 2215789Sahrens (srctype == ZFS_SRC_INHERITED)) { 2216924Sgjelinek (void) fprintf(stderr, gettext("could not verify zfs " 2217789Sahrens "dataset %s: mountpoint cannot be inherited\n"), 2218789Sahrens dstab.zone_dataset_name); 2219789Sahrens return_code = Z_ERR; 2220789Sahrens zfs_close(zhp); 2221789Sahrens continue; 2222789Sahrens } 2223789Sahrens 2224789Sahrens if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) { 2225789Sahrens (void) fprintf(stderr, gettext("cannot verify zfs " 2226789Sahrens "dataset %s: volumes cannot be specified as a " 2227789Sahrens "zone dataset resource\n"), 2228789Sahrens dstab.zone_dataset_name); 2229789Sahrens return_code = Z_ERR; 2230789Sahrens } 2231789Sahrens 2232789Sahrens if (zfs_iter_children(zhp, check_zvol, NULL) != 0) 2233789Sahrens return_code = Z_ERR; 2234789Sahrens 2235789Sahrens zfs_close(zhp); 2236789Sahrens } 2237789Sahrens (void) zonecfg_enddsent(handle); 2238789Sahrens 2239789Sahrens return (return_code); 2240789Sahrens } 2241789Sahrens 22420Sstevel@tonic-gate static int 22430Sstevel@tonic-gate verify_details(int cmd_num) 22440Sstevel@tonic-gate { 22450Sstevel@tonic-gate zone_dochandle_t handle; 22460Sstevel@tonic-gate struct zone_nwiftab nwiftab; 22470Sstevel@tonic-gate char zonepath[MAXPATHLEN], checkpath[MAXPATHLEN]; 22480Sstevel@tonic-gate int return_code = Z_OK; 22490Sstevel@tonic-gate int err; 2250766Scarlsonj boolean_t in_alt_root; 22510Sstevel@tonic-gate 22520Sstevel@tonic-gate if ((handle = zonecfg_init_handle()) == NULL) { 22530Sstevel@tonic-gate zperror(cmd_to_str(cmd_num), B_TRUE); 22540Sstevel@tonic-gate return (Z_ERR); 22550Sstevel@tonic-gate } 22560Sstevel@tonic-gate if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 22570Sstevel@tonic-gate errno = err; 22580Sstevel@tonic-gate zperror(cmd_to_str(cmd_num), B_TRUE); 22590Sstevel@tonic-gate zonecfg_fini_handle(handle); 22600Sstevel@tonic-gate return (Z_ERR); 22610Sstevel@tonic-gate } 22620Sstevel@tonic-gate if ((err = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath))) != 22630Sstevel@tonic-gate Z_OK) { 22640Sstevel@tonic-gate errno = err; 22650Sstevel@tonic-gate zperror(cmd_to_str(cmd_num), B_TRUE); 22660Sstevel@tonic-gate zonecfg_fini_handle(handle); 22670Sstevel@tonic-gate return (Z_ERR); 22680Sstevel@tonic-gate } 22690Sstevel@tonic-gate /* 22700Sstevel@tonic-gate * zonecfg_get_zonepath() gets its data from the XML repository. 22710Sstevel@tonic-gate * Verify this against the index file, which is checked first by 22720Sstevel@tonic-gate * zone_get_zonepath(). If they don't match, bail out. 22730Sstevel@tonic-gate */ 22740Sstevel@tonic-gate if ((err = zone_get_zonepath(target_zone, checkpath, 22750Sstevel@tonic-gate sizeof (checkpath))) != Z_OK) { 22760Sstevel@tonic-gate errno = err; 22770Sstevel@tonic-gate zperror2(target_zone, gettext("could not get zone path")); 22780Sstevel@tonic-gate return (Z_ERR); 22790Sstevel@tonic-gate } 22800Sstevel@tonic-gate if (strcmp(zonepath, checkpath) != 0) { 2281924Sgjelinek /* 2282924Sgjelinek * TRANSLATION_NOTE 2283924Sgjelinek * XML and zonepath are literals that should not be translated. 2284924Sgjelinek */ 22850Sstevel@tonic-gate (void) fprintf(stderr, gettext("The XML repository has " 22860Sstevel@tonic-gate "zonepath '%s',\nbut the index file has zonepath '%s'.\n" 22870Sstevel@tonic-gate "These must match, so fix the incorrect entry.\n"), 22880Sstevel@tonic-gate zonepath, checkpath); 22890Sstevel@tonic-gate return (Z_ERR); 22900Sstevel@tonic-gate } 22910Sstevel@tonic-gate if (validate_zonepath(zonepath, cmd_num) != Z_OK) { 22920Sstevel@tonic-gate (void) fprintf(stderr, gettext("could not verify zonepath %s " 22930Sstevel@tonic-gate "because of the above errors.\n"), zonepath); 22940Sstevel@tonic-gate return_code = Z_ERR; 22950Sstevel@tonic-gate } 22960Sstevel@tonic-gate 2297766Scarlsonj in_alt_root = zonecfg_in_alt_root(); 2298766Scarlsonj if (in_alt_root) 2299766Scarlsonj goto no_net; 2300766Scarlsonj 23010Sstevel@tonic-gate if ((err = zonecfg_setnwifent(handle)) != Z_OK) { 23020Sstevel@tonic-gate errno = err; 23030Sstevel@tonic-gate zperror(cmd_to_str(cmd_num), B_TRUE); 23040Sstevel@tonic-gate zonecfg_fini_handle(handle); 23050Sstevel@tonic-gate return (Z_ERR); 23060Sstevel@tonic-gate } 23070Sstevel@tonic-gate while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) { 23080Sstevel@tonic-gate struct lifreq lifr; 23090Sstevel@tonic-gate sa_family_t af; 23100Sstevel@tonic-gate int so, res; 23110Sstevel@tonic-gate 23120Sstevel@tonic-gate /* skip any loopback interfaces */ 23130Sstevel@tonic-gate if (strcmp(nwiftab.zone_nwif_physical, "lo0") == 0) 23140Sstevel@tonic-gate continue; 23150Sstevel@tonic-gate if ((res = zonecfg_valid_net_address(nwiftab.zone_nwif_address, 23160Sstevel@tonic-gate &lifr)) != Z_OK) { 23170Sstevel@tonic-gate (void) fprintf(stderr, gettext("could not verify %s " 23180Sstevel@tonic-gate "%s=%s %s=%s: %s\n"), "net", "address", 23190Sstevel@tonic-gate nwiftab.zone_nwif_address, "physical", 23200Sstevel@tonic-gate nwiftab.zone_nwif_physical, zonecfg_strerror(res)); 23210Sstevel@tonic-gate return_code = Z_ERR; 23220Sstevel@tonic-gate continue; 23230Sstevel@tonic-gate } 23240Sstevel@tonic-gate af = lifr.lifr_addr.ss_family; 23250Sstevel@tonic-gate (void) memset(&lifr, 0, sizeof (lifr)); 23260Sstevel@tonic-gate (void) strlcpy(lifr.lifr_name, nwiftab.zone_nwif_physical, 23270Sstevel@tonic-gate sizeof (lifr.lifr_name)); 23280Sstevel@tonic-gate lifr.lifr_addr.ss_family = af; 23290Sstevel@tonic-gate if ((so = socket(af, SOCK_DGRAM, 0)) < 0) { 23300Sstevel@tonic-gate (void) fprintf(stderr, gettext("could not verify %s " 23310Sstevel@tonic-gate "%s=%s %s=%s: could not get socket: %s\n"), "net", 23320Sstevel@tonic-gate "address", nwiftab.zone_nwif_address, "physical", 23330Sstevel@tonic-gate nwiftab.zone_nwif_physical, strerror(errno)); 23340Sstevel@tonic-gate return_code = Z_ERR; 23350Sstevel@tonic-gate continue; 23360Sstevel@tonic-gate } 23370Sstevel@tonic-gate if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 23380Sstevel@tonic-gate (void) fprintf(stderr, 23390Sstevel@tonic-gate gettext("could not verify %s %s=%s %s=%s: %s\n"), 23400Sstevel@tonic-gate "net", "address", nwiftab.zone_nwif_address, 23410Sstevel@tonic-gate "physical", nwiftab.zone_nwif_physical, 23420Sstevel@tonic-gate strerror(errno)); 23430Sstevel@tonic-gate return_code = Z_ERR; 23440Sstevel@tonic-gate } 23450Sstevel@tonic-gate (void) close(so); 23460Sstevel@tonic-gate } 23470Sstevel@tonic-gate (void) zonecfg_endnwifent(handle); 2348766Scarlsonj no_net: 23490Sstevel@tonic-gate 23500Sstevel@tonic-gate if (verify_filesystems(handle) != Z_OK) 23510Sstevel@tonic-gate return_code = Z_ERR; 2352823Sgjelinek if (verify_ipd(handle) != Z_OK) 2353823Sgjelinek return_code = Z_ERR; 2354766Scarlsonj if (!in_alt_root && verify_rctls(handle) != Z_OK) 23550Sstevel@tonic-gate return_code = Z_ERR; 2356766Scarlsonj if (!in_alt_root && verify_pool(handle) != Z_OK) 23570Sstevel@tonic-gate return_code = Z_ERR; 2358789Sahrens if (!in_alt_root && verify_datasets(handle) != Z_OK) 2359789Sahrens return_code = Z_ERR; 23600Sstevel@tonic-gate zonecfg_fini_handle(handle); 23610Sstevel@tonic-gate if (return_code == Z_ERR) 23620Sstevel@tonic-gate (void) fprintf(stderr, 23630Sstevel@tonic-gate gettext("%s: zone %s failed to verify\n"), 23640Sstevel@tonic-gate execname, target_zone); 23650Sstevel@tonic-gate return (return_code); 23660Sstevel@tonic-gate } 23670Sstevel@tonic-gate 23680Sstevel@tonic-gate static int 23690Sstevel@tonic-gate verify_func(int argc, char *argv[]) 23700Sstevel@tonic-gate { 23710Sstevel@tonic-gate int arg; 23720Sstevel@tonic-gate 23730Sstevel@tonic-gate optind = 0; 23740Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 23750Sstevel@tonic-gate switch (arg) { 23760Sstevel@tonic-gate case '?': 23770Sstevel@tonic-gate sub_usage(SHELP_VERIFY, CMD_VERIFY); 23780Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 23790Sstevel@tonic-gate default: 23800Sstevel@tonic-gate sub_usage(SHELP_VERIFY, CMD_VERIFY); 23810Sstevel@tonic-gate return (Z_USAGE); 23820Sstevel@tonic-gate } 23830Sstevel@tonic-gate } 23840Sstevel@tonic-gate if (argc > optind) { 23850Sstevel@tonic-gate sub_usage(SHELP_VERIFY, CMD_VERIFY); 23860Sstevel@tonic-gate return (Z_USAGE); 23870Sstevel@tonic-gate } 23880Sstevel@tonic-gate if (sanity_check(target_zone, CMD_VERIFY, B_FALSE, B_FALSE) != Z_OK) 23890Sstevel@tonic-gate return (Z_ERR); 23900Sstevel@tonic-gate return (verify_details(CMD_VERIFY)); 23910Sstevel@tonic-gate } 23920Sstevel@tonic-gate 23930Sstevel@tonic-gate #define LUCREATEZONE "/usr/lib/lu/lucreatezone" 23940Sstevel@tonic-gate 23950Sstevel@tonic-gate static int 23960Sstevel@tonic-gate install_func(int argc, char *argv[]) 23970Sstevel@tonic-gate { 23980Sstevel@tonic-gate /* 9: "exec " and " -z " */ 23990Sstevel@tonic-gate char cmdbuf[sizeof (LUCREATEZONE) + ZONENAME_MAX + 9]; 24000Sstevel@tonic-gate int lockfd; 24010Sstevel@tonic-gate int err, arg; 24020Sstevel@tonic-gate char zonepath[MAXPATHLEN]; 24030Sstevel@tonic-gate int status; 24040Sstevel@tonic-gate 2405766Scarlsonj if (zonecfg_in_alt_root()) { 2406766Scarlsonj zerror(gettext("cannot install zone in alternate root")); 2407766Scarlsonj return (Z_ERR); 2408766Scarlsonj } 2409766Scarlsonj 24100Sstevel@tonic-gate optind = 0; 24110Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 24120Sstevel@tonic-gate switch (arg) { 24130Sstevel@tonic-gate case '?': 24140Sstevel@tonic-gate sub_usage(SHELP_INSTALL, CMD_INSTALL); 24150Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 24160Sstevel@tonic-gate default: 24170Sstevel@tonic-gate sub_usage(SHELP_INSTALL, CMD_INSTALL); 24180Sstevel@tonic-gate return (Z_USAGE); 24190Sstevel@tonic-gate } 24200Sstevel@tonic-gate } 24210Sstevel@tonic-gate if (argc > optind) { 24220Sstevel@tonic-gate sub_usage(SHELP_INSTALL, CMD_INSTALL); 24230Sstevel@tonic-gate return (Z_USAGE); 24240Sstevel@tonic-gate } 24250Sstevel@tonic-gate if (sanity_check(target_zone, CMD_INSTALL, B_FALSE, B_TRUE) != Z_OK) 24260Sstevel@tonic-gate return (Z_ERR); 24270Sstevel@tonic-gate if (verify_details(CMD_INSTALL) != Z_OK) 24280Sstevel@tonic-gate return (Z_ERR); 24290Sstevel@tonic-gate 24300Sstevel@tonic-gate if (grab_lock_file(target_zone, &lockfd) != Z_OK) { 24310Sstevel@tonic-gate zerror(gettext("another %s may have an operation in progress."), 24321300Sgjelinek "zoneadm"); 24330Sstevel@tonic-gate return (Z_ERR); 24340Sstevel@tonic-gate } 24350Sstevel@tonic-gate err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE); 24360Sstevel@tonic-gate if (err != Z_OK) { 24370Sstevel@tonic-gate errno = err; 24380Sstevel@tonic-gate zperror2(target_zone, gettext("could not set state")); 24390Sstevel@tonic-gate goto done; 24400Sstevel@tonic-gate } 24410Sstevel@tonic-gate 24420Sstevel@tonic-gate /* 24430Sstevel@tonic-gate * According to the Application Packaging Developer's Guide, a 24440Sstevel@tonic-gate * "checkinstall" script when included in a package is executed as 24450Sstevel@tonic-gate * the user "install", if such a user exists, or by the user 24460Sstevel@tonic-gate * "nobody". In order to support this dubious behavior, the path 24470Sstevel@tonic-gate * to the zone being constructed is opened up during the life of 24480Sstevel@tonic-gate * the command laying down the zone's root file system. Once this 24490Sstevel@tonic-gate * has completed, regardless of whether it was successful, the 24500Sstevel@tonic-gate * path to the zone is again restricted. 24510Sstevel@tonic-gate */ 24520Sstevel@tonic-gate if ((err = zone_get_zonepath(target_zone, zonepath, 24530Sstevel@tonic-gate sizeof (zonepath))) != Z_OK) { 24540Sstevel@tonic-gate errno = err; 24550Sstevel@tonic-gate zperror2(target_zone, gettext("could not get zone path")); 24560Sstevel@tonic-gate goto done; 24570Sstevel@tonic-gate } 24580Sstevel@tonic-gate if (chmod(zonepath, DEFAULT_DIR_MODE) != 0) { 24590Sstevel@tonic-gate zperror(zonepath, B_FALSE); 24600Sstevel@tonic-gate err = Z_ERR; 24610Sstevel@tonic-gate goto done; 24620Sstevel@tonic-gate } 24630Sstevel@tonic-gate 24640Sstevel@tonic-gate /* 24650Sstevel@tonic-gate * "exec" the command so that the returned status is that of 24660Sstevel@tonic-gate * LUCREATEZONE and not the shell. 24670Sstevel@tonic-gate */ 24680Sstevel@tonic-gate (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " LUCREATEZONE " -z %s", 24690Sstevel@tonic-gate target_zone); 24700Sstevel@tonic-gate status = do_subproc(cmdbuf); 24710Sstevel@tonic-gate if (chmod(zonepath, S_IRWXU) != 0) { 24720Sstevel@tonic-gate zperror(zonepath, B_FALSE); 24730Sstevel@tonic-gate err = Z_ERR; 24740Sstevel@tonic-gate goto done; 24750Sstevel@tonic-gate } 24760Sstevel@tonic-gate if ((err = subproc_status(LUCREATEZONE, status)) != Z_OK) 24770Sstevel@tonic-gate goto done; 24780Sstevel@tonic-gate 24790Sstevel@tonic-gate if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) { 24800Sstevel@tonic-gate errno = err; 24810Sstevel@tonic-gate zperror2(target_zone, gettext("could not set state")); 24820Sstevel@tonic-gate goto done; 24830Sstevel@tonic-gate } 24840Sstevel@tonic-gate 24850Sstevel@tonic-gate done: 24860Sstevel@tonic-gate release_lock_file(lockfd); 24870Sstevel@tonic-gate return ((err == Z_OK) ? Z_OK : Z_ERR); 24880Sstevel@tonic-gate } 24890Sstevel@tonic-gate 24900Sstevel@tonic-gate /* 24911300Sgjelinek * Check that the inherited pkg dirs are the same for the clone and its source. 24921300Sgjelinek * The easiest way to do that is check that the list of ipds is the same 24931300Sgjelinek * by matching each one against the other. This algorithm should be fine since 24941300Sgjelinek * the list of ipds should not be that long. 24951300Sgjelinek */ 24961300Sgjelinek static int 24971300Sgjelinek valid_ipd_clone(zone_dochandle_t s_handle, char *source_zone, 24981300Sgjelinek zone_dochandle_t t_handle, char *target_zone) 24991300Sgjelinek { 25001300Sgjelinek int err; 25011300Sgjelinek int res = Z_OK; 25021300Sgjelinek int s_cnt = 0; 25031300Sgjelinek int t_cnt = 0; 25041300Sgjelinek struct zone_fstab s_fstab; 25051300Sgjelinek struct zone_fstab t_fstab; 25061300Sgjelinek 25071300Sgjelinek /* 25081300Sgjelinek * First check the source of the clone against the target. 25091300Sgjelinek */ 25101300Sgjelinek if ((err = zonecfg_setipdent(s_handle)) != Z_OK) { 25111300Sgjelinek errno = err; 25121300Sgjelinek zperror2(source_zone, gettext("could not enumerate " 25131300Sgjelinek "inherit-pkg-dirs")); 25141300Sgjelinek return (Z_ERR); 25151300Sgjelinek } 25161300Sgjelinek 25171300Sgjelinek while (zonecfg_getipdent(s_handle, &s_fstab) == Z_OK) { 25181300Sgjelinek boolean_t match = B_FALSE; 25191300Sgjelinek 25201300Sgjelinek s_cnt++; 25211300Sgjelinek 25221300Sgjelinek if ((err = zonecfg_setipdent(t_handle)) != Z_OK) { 25231300Sgjelinek errno = err; 25241300Sgjelinek zperror2(target_zone, gettext("could not enumerate " 25251300Sgjelinek "inherit-pkg-dirs")); 25261300Sgjelinek (void) zonecfg_endipdent(s_handle); 25271300Sgjelinek return (Z_ERR); 25281300Sgjelinek } 25291300Sgjelinek 25301300Sgjelinek while (zonecfg_getipdent(t_handle, &t_fstab) == Z_OK) { 25311300Sgjelinek if (strcmp(s_fstab.zone_fs_dir, t_fstab.zone_fs_dir) 25321300Sgjelinek == 0) { 25331300Sgjelinek match = B_TRUE; 25341300Sgjelinek break; 25351300Sgjelinek } 25361300Sgjelinek } 25371300Sgjelinek (void) zonecfg_endipdent(t_handle); 25381300Sgjelinek 25391300Sgjelinek if (!match) { 25401300Sgjelinek (void) fprintf(stderr, gettext("inherit-pkg-dir " 25411300Sgjelinek "'%s' is not configured in zone %s.\n"), 25421300Sgjelinek s_fstab.zone_fs_dir, target_zone); 25431300Sgjelinek res = Z_ERR; 25441300Sgjelinek } 25451300Sgjelinek } 25461300Sgjelinek 25471300Sgjelinek (void) zonecfg_endipdent(s_handle); 25481300Sgjelinek 25491300Sgjelinek /* skip the next check if we already have errors */ 25501300Sgjelinek if (res == Z_ERR) 25511300Sgjelinek return (res); 25521300Sgjelinek 25531300Sgjelinek /* 25541300Sgjelinek * Now check the number of ipds in the target so we can verify 25551300Sgjelinek * that the source is not a subset of the target. 25561300Sgjelinek */ 25571300Sgjelinek if ((err = zonecfg_setipdent(t_handle)) != Z_OK) { 25581300Sgjelinek errno = err; 25591300Sgjelinek zperror2(target_zone, gettext("could not enumerate " 25601300Sgjelinek "inherit-pkg-dirs")); 25611300Sgjelinek return (Z_ERR); 25621300Sgjelinek } 25631300Sgjelinek 25641300Sgjelinek while (zonecfg_getipdent(t_handle, &t_fstab) == Z_OK) 25651300Sgjelinek t_cnt++; 25661300Sgjelinek 25671300Sgjelinek (void) zonecfg_endipdent(t_handle); 25681300Sgjelinek 25691300Sgjelinek if (t_cnt != s_cnt) { 25701300Sgjelinek (void) fprintf(stderr, gettext("Zone %s is configured " 25711300Sgjelinek "with inherit-pkg-dirs that are not configured in zone " 25721300Sgjelinek "%s.\n"), target_zone, source_zone); 25731300Sgjelinek res = Z_ERR; 25741300Sgjelinek } 25751300Sgjelinek 25761300Sgjelinek return (res); 25771300Sgjelinek } 25781300Sgjelinek 25791300Sgjelinek static void 25801300Sgjelinek warn_dev_match(zone_dochandle_t s_handle, char *source_zone, 25811300Sgjelinek zone_dochandle_t t_handle, char *target_zone) 25821300Sgjelinek { 25831300Sgjelinek int err; 25841300Sgjelinek struct zone_devtab s_devtab; 25851300Sgjelinek struct zone_devtab t_devtab; 25861300Sgjelinek 25871300Sgjelinek if ((err = zonecfg_setdevent(t_handle)) != Z_OK) { 25881300Sgjelinek errno = err; 25891300Sgjelinek zperror2(target_zone, gettext("could not enumerate devices")); 25901300Sgjelinek return; 25911300Sgjelinek } 25921300Sgjelinek 25931300Sgjelinek while (zonecfg_getdevent(t_handle, &t_devtab) == Z_OK) { 25941300Sgjelinek if ((err = zonecfg_setdevent(s_handle)) != Z_OK) { 25951300Sgjelinek errno = err; 25961300Sgjelinek zperror2(source_zone, 25971300Sgjelinek gettext("could not enumerate devices")); 25981300Sgjelinek (void) zonecfg_enddevent(t_handle); 25991300Sgjelinek return; 26001300Sgjelinek } 26011300Sgjelinek 26021300Sgjelinek while (zonecfg_getdevent(s_handle, &s_devtab) == Z_OK) { 26031300Sgjelinek /* 26041300Sgjelinek * Use fnmatch to catch the case where wildcards 26051300Sgjelinek * were used in one zone and the other has an 26061300Sgjelinek * explicit entry (e.g. /dev/dsk/c0t0d0s6 vs. 26071300Sgjelinek * /dev/\*dsk/c0t0d0s6). 26081300Sgjelinek */ 26091300Sgjelinek if (fnmatch(t_devtab.zone_dev_match, 26101300Sgjelinek s_devtab.zone_dev_match, FNM_PATHNAME) == 0 || 26111300Sgjelinek fnmatch(s_devtab.zone_dev_match, 26121300Sgjelinek t_devtab.zone_dev_match, FNM_PATHNAME) == 0) { 26131300Sgjelinek (void) fprintf(stderr, 26141300Sgjelinek gettext("WARNING: device '%s' " 26151300Sgjelinek "is configured in both zones.\n"), 26161300Sgjelinek t_devtab.zone_dev_match); 26171300Sgjelinek break; 26181300Sgjelinek } 26191300Sgjelinek } 26201300Sgjelinek (void) zonecfg_enddevent(s_handle); 26211300Sgjelinek } 26221300Sgjelinek 26231300Sgjelinek (void) zonecfg_enddevent(t_handle); 26241300Sgjelinek } 26251300Sgjelinek 26261300Sgjelinek /* 26271300Sgjelinek * Check if the specified mount option (opt) is contained within the 26281300Sgjelinek * options string. 26291300Sgjelinek */ 26301300Sgjelinek static boolean_t 26311300Sgjelinek opt_match(char *opt, char *options) 26321300Sgjelinek { 26331300Sgjelinek char *p; 26341300Sgjelinek char *lastp; 26351300Sgjelinek 26361300Sgjelinek if ((p = strtok_r(options, ",", &lastp)) != NULL) { 26371300Sgjelinek if (strcmp(p, opt) == 0) 26381300Sgjelinek return (B_TRUE); 26391300Sgjelinek while ((p = strtok_r(NULL, ",", &lastp)) != NULL) { 26401300Sgjelinek if (strcmp(p, opt) == 0) 26411300Sgjelinek return (B_TRUE); 26421300Sgjelinek } 26431300Sgjelinek } 26441300Sgjelinek 26451300Sgjelinek return (B_FALSE); 26461300Sgjelinek } 26471300Sgjelinek 26481300Sgjelinek #define RW_LOFS "WARNING: read-write lofs file-system on '%s' is configured " \ 26491300Sgjelinek "in both zones.\n" 26501300Sgjelinek 26511300Sgjelinek static void 26521300Sgjelinek print_fs_warnings(struct zone_fstab *s_fstab, struct zone_fstab *t_fstab) 26531300Sgjelinek { 26541300Sgjelinek /* 26551300Sgjelinek * It is ok to have shared lofs mounted fs but we want to warn if 26561300Sgjelinek * either is rw since this will effect the other zone. 26571300Sgjelinek */ 26581300Sgjelinek if (strcmp(t_fstab->zone_fs_type, "lofs") == 0) { 26591300Sgjelinek zone_fsopt_t *optp; 26601300Sgjelinek 26611300Sgjelinek /* The default is rw so no options means rw */ 26621300Sgjelinek if (t_fstab->zone_fs_options == NULL || 26631300Sgjelinek s_fstab->zone_fs_options == NULL) { 26641300Sgjelinek (void) fprintf(stderr, gettext(RW_LOFS), 26651300Sgjelinek t_fstab->zone_fs_special); 26661300Sgjelinek return; 26671300Sgjelinek } 26681300Sgjelinek 26691300Sgjelinek for (optp = s_fstab->zone_fs_options; optp != NULL; 26701300Sgjelinek optp = optp->zone_fsopt_next) { 26711300Sgjelinek if (opt_match("rw", optp->zone_fsopt_opt)) { 26721300Sgjelinek (void) fprintf(stderr, gettext(RW_LOFS), 26731300Sgjelinek s_fstab->zone_fs_special); 26741300Sgjelinek return; 26751300Sgjelinek } 26761300Sgjelinek } 26771300Sgjelinek 26781300Sgjelinek for (optp = t_fstab->zone_fs_options; optp != NULL; 26791300Sgjelinek optp = optp->zone_fsopt_next) { 26801300Sgjelinek if (opt_match("rw", optp->zone_fsopt_opt)) { 26811300Sgjelinek (void) fprintf(stderr, gettext(RW_LOFS), 26821300Sgjelinek t_fstab->zone_fs_special); 26831300Sgjelinek return; 26841300Sgjelinek } 26851300Sgjelinek } 26861300Sgjelinek 26871300Sgjelinek return; 26881300Sgjelinek } 26891300Sgjelinek 26901300Sgjelinek /* 26911300Sgjelinek * TRANSLATION_NOTE 26921300Sgjelinek * The first variable is the file-system type and the second is 26931300Sgjelinek * the file-system special device. For example, 26941300Sgjelinek * WARNING: ufs file-system on '/dev/dsk/c0t0d0s0' ... 26951300Sgjelinek */ 26961300Sgjelinek (void) fprintf(stderr, gettext("WARNING: %s file-system on '%s' " 26971300Sgjelinek "is configured in both zones.\n"), t_fstab->zone_fs_type, 26981300Sgjelinek t_fstab->zone_fs_special); 26991300Sgjelinek } 27001300Sgjelinek 27011300Sgjelinek static void 27021300Sgjelinek warn_fs_match(zone_dochandle_t s_handle, char *source_zone, 27031300Sgjelinek zone_dochandle_t t_handle, char *target_zone) 27041300Sgjelinek { 27051300Sgjelinek int err; 27061300Sgjelinek struct zone_fstab s_fstab; 27071300Sgjelinek struct zone_fstab t_fstab; 27081300Sgjelinek 27091300Sgjelinek if ((err = zonecfg_setfsent(t_handle)) != Z_OK) { 27101300Sgjelinek errno = err; 27111300Sgjelinek zperror2(target_zone, 27121300Sgjelinek gettext("could not enumerate file-systems")); 27131300Sgjelinek return; 27141300Sgjelinek } 27151300Sgjelinek 27161300Sgjelinek while (zonecfg_getfsent(t_handle, &t_fstab) == Z_OK) { 27171300Sgjelinek if ((err = zonecfg_setfsent(s_handle)) != Z_OK) { 27181300Sgjelinek errno = err; 27191300Sgjelinek zperror2(source_zone, 27201300Sgjelinek gettext("could not enumerate file-systems")); 27211300Sgjelinek (void) zonecfg_endfsent(t_handle); 27221300Sgjelinek return; 27231300Sgjelinek } 27241300Sgjelinek 27251300Sgjelinek while (zonecfg_getfsent(s_handle, &s_fstab) == Z_OK) { 27261300Sgjelinek if (strcmp(t_fstab.zone_fs_special, 27271300Sgjelinek s_fstab.zone_fs_special) == 0) { 27281300Sgjelinek print_fs_warnings(&s_fstab, &t_fstab); 27291300Sgjelinek break; 27301300Sgjelinek } 27311300Sgjelinek } 27321300Sgjelinek (void) zonecfg_endfsent(s_handle); 27331300Sgjelinek } 27341300Sgjelinek 27351300Sgjelinek (void) zonecfg_endfsent(t_handle); 27361300Sgjelinek } 27371300Sgjelinek 27381300Sgjelinek /* 27391300Sgjelinek * We don't catch the case where you used the same IP address but 27401300Sgjelinek * it is not an exact string match. For example, 192.9.0.128 vs. 192.09.0.128. 27411300Sgjelinek * However, we're not going to worry about that but we will check for 27421300Sgjelinek * a possible netmask on one of the addresses (e.g. 10.0.0.1 and 10.0.0.1/24) 27431300Sgjelinek * and handle that case as a match. 27441300Sgjelinek */ 27451300Sgjelinek static void 27461300Sgjelinek warn_ip_match(zone_dochandle_t s_handle, char *source_zone, 27471300Sgjelinek zone_dochandle_t t_handle, char *target_zone) 27481300Sgjelinek { 27491300Sgjelinek int err; 27501300Sgjelinek struct zone_nwiftab s_nwiftab; 27511300Sgjelinek struct zone_nwiftab t_nwiftab; 27521300Sgjelinek 27531300Sgjelinek if ((err = zonecfg_setnwifent(t_handle)) != Z_OK) { 27541300Sgjelinek errno = err; 27551300Sgjelinek zperror2(target_zone, 27561300Sgjelinek gettext("could not enumerate network interfaces")); 27571300Sgjelinek return; 27581300Sgjelinek } 27591300Sgjelinek 27601300Sgjelinek while (zonecfg_getnwifent(t_handle, &t_nwiftab) == Z_OK) { 27611300Sgjelinek char *p; 27621300Sgjelinek 27631300Sgjelinek /* remove an (optional) netmask from the address */ 27641300Sgjelinek if ((p = strchr(t_nwiftab.zone_nwif_address, '/')) != NULL) 27651300Sgjelinek *p = '\0'; 27661300Sgjelinek 27671300Sgjelinek if ((err = zonecfg_setnwifent(s_handle)) != Z_OK) { 27681300Sgjelinek errno = err; 27691300Sgjelinek zperror2(source_zone, 27701300Sgjelinek gettext("could not enumerate network interfaces")); 27711300Sgjelinek (void) zonecfg_endnwifent(t_handle); 27721300Sgjelinek return; 27731300Sgjelinek } 27741300Sgjelinek 27751300Sgjelinek while (zonecfg_getnwifent(s_handle, &s_nwiftab) == Z_OK) { 27761300Sgjelinek /* remove an (optional) netmask from the address */ 27771300Sgjelinek if ((p = strchr(s_nwiftab.zone_nwif_address, '/')) 27781300Sgjelinek != NULL) 27791300Sgjelinek *p = '\0'; 27801300Sgjelinek 27811300Sgjelinek if (strcmp(t_nwiftab.zone_nwif_address, 27821300Sgjelinek s_nwiftab.zone_nwif_address) == 0) { 27831300Sgjelinek (void) fprintf(stderr, 27841300Sgjelinek gettext("WARNING: network address '%s' " 27851300Sgjelinek "is configured in both zones.\n"), 27861300Sgjelinek t_nwiftab.zone_nwif_address); 27871300Sgjelinek break; 27881300Sgjelinek } 27891300Sgjelinek } 27901300Sgjelinek (void) zonecfg_endnwifent(s_handle); 27911300Sgjelinek } 27921300Sgjelinek 27931300Sgjelinek (void) zonecfg_endnwifent(t_handle); 27941300Sgjelinek } 27951300Sgjelinek 27961300Sgjelinek static void 27971300Sgjelinek warn_dataset_match(zone_dochandle_t s_handle, char *source_zone, 27981300Sgjelinek zone_dochandle_t t_handle, char *target_zone) 27991300Sgjelinek { 28001300Sgjelinek int err; 28011300Sgjelinek struct zone_dstab s_dstab; 28021300Sgjelinek struct zone_dstab t_dstab; 28031300Sgjelinek 28041300Sgjelinek if ((err = zonecfg_setdsent(t_handle)) != Z_OK) { 28051300Sgjelinek errno = err; 28061300Sgjelinek zperror2(target_zone, gettext("could not enumerate datasets")); 28071300Sgjelinek return; 28081300Sgjelinek } 28091300Sgjelinek 28101300Sgjelinek while (zonecfg_getdsent(t_handle, &t_dstab) == Z_OK) { 28111300Sgjelinek if ((err = zonecfg_setdsent(s_handle)) != Z_OK) { 28121300Sgjelinek errno = err; 28131300Sgjelinek zperror2(source_zone, 28141300Sgjelinek gettext("could not enumerate datasets")); 28151300Sgjelinek (void) zonecfg_enddsent(t_handle); 28161300Sgjelinek return; 28171300Sgjelinek } 28181300Sgjelinek 28191300Sgjelinek while (zonecfg_getdsent(s_handle, &s_dstab) == Z_OK) { 28201300Sgjelinek if (strcmp(t_dstab.zone_dataset_name, 28211300Sgjelinek s_dstab.zone_dataset_name) == 0) { 28221300Sgjelinek (void) fprintf(stderr, 28231300Sgjelinek gettext("WARNING: dataset '%s' " 28241300Sgjelinek "is configured in both zones.\n"), 28251300Sgjelinek t_dstab.zone_dataset_name); 28261300Sgjelinek break; 28271300Sgjelinek } 28281300Sgjelinek } 28291300Sgjelinek (void) zonecfg_enddsent(s_handle); 28301300Sgjelinek } 28311300Sgjelinek 28321300Sgjelinek (void) zonecfg_enddsent(t_handle); 28331300Sgjelinek } 28341300Sgjelinek 28351300Sgjelinek static int 28361300Sgjelinek validate_clone(char *source_zone, char *target_zone) 28371300Sgjelinek { 28381300Sgjelinek int err = Z_OK; 28391300Sgjelinek zone_dochandle_t s_handle; 28401300Sgjelinek zone_dochandle_t t_handle; 28411300Sgjelinek 28421300Sgjelinek if ((t_handle = zonecfg_init_handle()) == NULL) { 28431300Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 28441300Sgjelinek return (Z_ERR); 28451300Sgjelinek } 28461300Sgjelinek if ((err = zonecfg_get_handle(target_zone, t_handle)) != Z_OK) { 28471300Sgjelinek errno = err; 28481300Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 28491300Sgjelinek zonecfg_fini_handle(t_handle); 28501300Sgjelinek return (Z_ERR); 28511300Sgjelinek } 28521300Sgjelinek 28531300Sgjelinek if ((s_handle = zonecfg_init_handle()) == NULL) { 28541300Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 28551300Sgjelinek zonecfg_fini_handle(t_handle); 28561300Sgjelinek return (Z_ERR); 28571300Sgjelinek } 28581300Sgjelinek if ((err = zonecfg_get_handle(source_zone, s_handle)) != Z_OK) { 28591300Sgjelinek errno = err; 28601300Sgjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE); 28611300Sgjelinek goto done; 28621300Sgjelinek } 28631300Sgjelinek 28641300Sgjelinek /* verify new zone has same inherit-pkg-dirs */ 28651300Sgjelinek err = valid_ipd_clone(s_handle, source_zone, t_handle, target_zone); 28661300Sgjelinek 28671300Sgjelinek /* warn about imported fs's which are the same */ 28681300Sgjelinek warn_fs_match(s_handle, source_zone, t_handle, target_zone); 28691300Sgjelinek 28701300Sgjelinek /* warn about imported IP addresses which are the same */ 28711300Sgjelinek warn_ip_match(s_handle, source_zone, t_handle, target_zone); 28721300Sgjelinek 28731300Sgjelinek /* warn about imported devices which are the same */ 28741300Sgjelinek warn_dev_match(s_handle, source_zone, t_handle, target_zone); 28751300Sgjelinek 28761300Sgjelinek /* warn about imported datasets which are the same */ 28771300Sgjelinek warn_dataset_match(s_handle, source_zone, t_handle, target_zone); 28781300Sgjelinek 28791300Sgjelinek done: 28801300Sgjelinek zonecfg_fini_handle(t_handle); 28811300Sgjelinek zonecfg_fini_handle(s_handle); 28821300Sgjelinek 28831300Sgjelinek return ((err == Z_OK) ? Z_OK : Z_ERR); 28841300Sgjelinek } 28851300Sgjelinek 28861300Sgjelinek static int 28871300Sgjelinek copy_zone(char *src, char *dst) 28881300Sgjelinek { 28891300Sgjelinek boolean_t out_null = B_FALSE; 28901300Sgjelinek int status; 28911300Sgjelinek int err; 28921300Sgjelinek char *outfile; 28931300Sgjelinek char cmdbuf[MAXPATHLEN * 2 + 128]; 28941300Sgjelinek 28951300Sgjelinek if ((outfile = tempnam("/var/log", "zone")) == NULL) { 28961300Sgjelinek outfile = "/dev/null"; 28971300Sgjelinek out_null = B_TRUE; 28981300Sgjelinek } 28991300Sgjelinek 29001300Sgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), 29011300Sgjelinek "cd %s && /usr/bin/find . -depth -print | " 29021300Sgjelinek "/usr/bin/cpio -pdmuP@ %s > %s 2>&1", 29031300Sgjelinek src, dst, outfile); 29041300Sgjelinek 29051300Sgjelinek status = do_subproc(cmdbuf); 29061300Sgjelinek 29071300Sgjelinek if ((err = subproc_status("copy", status)) != Z_OK) { 29081300Sgjelinek if (!out_null) 29091300Sgjelinek (void) fprintf(stderr, gettext("\nThe copy failed.\n" 29101300Sgjelinek "More information can be found in %s\n"), outfile); 29111300Sgjelinek return (err); 29121300Sgjelinek } 29131300Sgjelinek 29141300Sgjelinek if (!out_null) 29151300Sgjelinek (void) unlink(outfile); 29161300Sgjelinek 29171300Sgjelinek return (Z_OK); 29181300Sgjelinek } 29191300Sgjelinek 29201300Sgjelinek /* 29211300Sgjelinek * Wait until the target_zone has booted to single-user. Return Z_OK once 29221300Sgjelinek * the zone has booted to that level or return Z_BAD_ZONE_STATE if the zone 29231300Sgjelinek * has not booted to single-user after the timeout. 29241300Sgjelinek */ 29251300Sgjelinek static int 29261300Sgjelinek zone_wait_single_user() 29271300Sgjelinek { 29281300Sgjelinek char cmdbuf[ZONENAME_MAX + 256]; 29291300Sgjelinek int retry; 29301300Sgjelinek 29311300Sgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), 29321300Sgjelinek "test \"`/usr/sbin/zlogin -S %s /usr/bin/svcprop -p " 29331300Sgjelinek "restarter/state svc:/milestone/single-user:default 2>/dev/null`\" " 29341300Sgjelinek "= \"online\"", 29351300Sgjelinek target_zone); 29361300Sgjelinek 29371300Sgjelinek for (retry = 0; retry < SINGLE_USER_RETRY; retry++) { 29381300Sgjelinek int status; 29391300Sgjelinek 29401300Sgjelinek status = do_subproc(cmdbuf); 29411300Sgjelinek if (WIFEXITED(status)) { 29421300Sgjelinek if (WEXITSTATUS(status) == 0) 29431300Sgjelinek return (Z_OK); 29441300Sgjelinek 29451300Sgjelinek (void) sleep(2); 29461300Sgjelinek } else { 29471300Sgjelinek return (Z_BAD_ZONE_STATE); 29481300Sgjelinek } 29491300Sgjelinek } 29501300Sgjelinek 29511300Sgjelinek return (Z_BAD_ZONE_STATE); 29521300Sgjelinek } 29531300Sgjelinek 29541300Sgjelinek 29551300Sgjelinek /* ARGSUSED */ 29561300Sgjelinek int 29571300Sgjelinek zfm_print(const char *p, void *r) { 29581300Sgjelinek zerror(" %s\n", p); 29591300Sgjelinek return (0); 29601300Sgjelinek } 29611300Sgjelinek 29621300Sgjelinek static int 29631300Sgjelinek clone_func(int argc, char *argv[]) 29641300Sgjelinek { 29651300Sgjelinek char cmdbuf[MAXPATHLEN]; 29661300Sgjelinek char *source_zone = NULL; 29671300Sgjelinek int lockfd; 29681300Sgjelinek int err, arg; 29691300Sgjelinek char zonepath[MAXPATHLEN]; 29701300Sgjelinek char source_zonepath[MAXPATHLEN]; 29711300Sgjelinek int status; 29721300Sgjelinek zone_state_t state; 29731300Sgjelinek zone_entry_t *zent; 29741300Sgjelinek char *method = "copy"; 29751300Sgjelinek char *boot_args[] = { "-s", NULL }; 29761300Sgjelinek char *halt_args[] = { NULL }; 29771300Sgjelinek struct stat unconfig_buf; 29781300Sgjelinek boolean_t revert; 29791300Sgjelinek 29801300Sgjelinek if (zonecfg_in_alt_root()) { 29811300Sgjelinek zerror(gettext("cannot clone zone in alternate root")); 29821300Sgjelinek return (Z_ERR); 29831300Sgjelinek } 29841300Sgjelinek 29851300Sgjelinek optind = 0; 29861300Sgjelinek if ((arg = getopt(argc, argv, "?m:")) != EOF) { 29871300Sgjelinek switch (arg) { 29881300Sgjelinek case '?': 29891300Sgjelinek sub_usage(SHELP_CLONE, CMD_CLONE); 29901300Sgjelinek return (optopt == '?' ? Z_OK : Z_USAGE); 29911300Sgjelinek case 'm': 29921300Sgjelinek method = optarg; 29931300Sgjelinek break; 29941300Sgjelinek default: 29951300Sgjelinek sub_usage(SHELP_CLONE, CMD_CLONE); 29961300Sgjelinek return (Z_USAGE); 29971300Sgjelinek } 29981300Sgjelinek } 29991300Sgjelinek if (argc != (optind + 1) || strcmp(method, "copy") != 0) { 30001300Sgjelinek sub_usage(SHELP_CLONE, CMD_CLONE); 30011300Sgjelinek return (Z_USAGE); 30021300Sgjelinek } 30031300Sgjelinek source_zone = argv[optind]; 30041300Sgjelinek if (sanity_check(target_zone, CMD_CLONE, B_FALSE, B_TRUE) != Z_OK) 30051300Sgjelinek return (Z_ERR); 30061300Sgjelinek if (verify_details(CMD_CLONE) != Z_OK) 30071300Sgjelinek return (Z_ERR); 30081300Sgjelinek 30091300Sgjelinek /* 30101300Sgjelinek * We also need to do some extra validation on the source zone. 30111300Sgjelinek */ 30121300Sgjelinek 30131300Sgjelinek if (strcmp(source_zone, GLOBAL_ZONENAME) == 0) { 30141300Sgjelinek zerror(gettext("%s operation is invalid for the global zone."), 30151300Sgjelinek cmd_to_str(CMD_CLONE)); 30161300Sgjelinek return (Z_ERR); 30171300Sgjelinek } 30181300Sgjelinek 30191300Sgjelinek if (strncmp(source_zone, "SUNW", 4) == 0) { 30201300Sgjelinek zerror(gettext("%s operation is invalid for zones starting " 30211300Sgjelinek "with SUNW."), cmd_to_str(CMD_CLONE)); 30221300Sgjelinek return (Z_ERR); 30231300Sgjelinek } 30241300Sgjelinek 30251300Sgjelinek zent = lookup_running_zone(source_zone); 30261300Sgjelinek if (zent != NULL) { 30271300Sgjelinek /* check whether the zone is ready or running */ 30281300Sgjelinek if ((err = zone_get_state(zent->zname, &zent->zstate_num)) 30291300Sgjelinek != Z_OK) { 30301300Sgjelinek errno = err; 30311300Sgjelinek zperror2(zent->zname, gettext("could not get state")); 30321300Sgjelinek /* can't tell, so hedge */ 30331300Sgjelinek zent->zstate_str = "ready/running"; 30341300Sgjelinek } else { 30351300Sgjelinek zent->zstate_str = zone_state_str(zent->zstate_num); 30361300Sgjelinek } 30371300Sgjelinek zerror(gettext("%s operation is invalid for %s zones."), 30381300Sgjelinek cmd_to_str(CMD_CLONE), zent->zstate_str); 30391300Sgjelinek return (Z_ERR); 30401300Sgjelinek } 30411300Sgjelinek 30421300Sgjelinek if ((err = zone_get_state(source_zone, &state)) != Z_OK) { 30431300Sgjelinek errno = err; 30441300Sgjelinek zperror2(source_zone, gettext("could not get state")); 30451300Sgjelinek return (Z_ERR); 30461300Sgjelinek } 30471300Sgjelinek if (state != ZONE_STATE_INSTALLED) { 30481300Sgjelinek (void) fprintf(stderr, 30491300Sgjelinek gettext("%s: zone %s is %s; %s is required.\n"), 30501300Sgjelinek execname, source_zone, zone_state_str(state), 30511300Sgjelinek zone_state_str(ZONE_STATE_INSTALLED)); 30521300Sgjelinek return (Z_ERR); 30531300Sgjelinek } 30541300Sgjelinek 30551300Sgjelinek /* 30561300Sgjelinek * The source zone checks out ok, continue with the clone. 30571300Sgjelinek */ 30581300Sgjelinek 30591300Sgjelinek if (validate_clone(source_zone, target_zone) != Z_OK) 30601300Sgjelinek return (Z_ERR); 30611300Sgjelinek 30621300Sgjelinek if (grab_lock_file(target_zone, &lockfd) != Z_OK) { 30631300Sgjelinek zerror(gettext("another %s may have an operation in progress."), 30641300Sgjelinek "zoneadm"); 30651300Sgjelinek return (Z_ERR); 30661300Sgjelinek } 30671300Sgjelinek 30681300Sgjelinek if ((err = zone_get_zonepath(source_zone, source_zonepath, 30691300Sgjelinek sizeof (source_zonepath))) != Z_OK) { 30701300Sgjelinek errno = err; 30711300Sgjelinek zperror2(source_zone, gettext("could not get zone path")); 30721300Sgjelinek goto done; 30731300Sgjelinek } 30741300Sgjelinek 30751300Sgjelinek if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath))) 30761300Sgjelinek != Z_OK) { 30771300Sgjelinek errno = err; 30781300Sgjelinek zperror2(target_zone, gettext("could not get zone path")); 30791300Sgjelinek goto done; 30801300Sgjelinek } 30811300Sgjelinek 30821300Sgjelinek /* Don't clone the zone if anything is still mounted there */ 30831300Sgjelinek if (zonecfg_find_mounts(source_zonepath, NULL, NULL)) { 30841300Sgjelinek zerror(gettext("These file-systems are mounted on " 30851300Sgjelinek "subdirectories of %s.\n"), source_zonepath); 30861300Sgjelinek (void) zonecfg_find_mounts(source_zonepath, zfm_print, NULL); 30871300Sgjelinek err = Z_ERR; 30881300Sgjelinek goto done; 30891300Sgjelinek } 30901300Sgjelinek 30911300Sgjelinek if ((err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE)) 30921300Sgjelinek != Z_OK) { 30931300Sgjelinek errno = err; 30941300Sgjelinek zperror2(target_zone, gettext("could not set state")); 30951300Sgjelinek goto done; 30961300Sgjelinek } 30971300Sgjelinek 30981300Sgjelinek (void) printf(gettext("Cloning zonepath %s..."), source_zonepath); 30991300Sgjelinek (void) fflush(stdout); 31001300Sgjelinek 31011300Sgjelinek if ((err = copy_zone(source_zonepath, zonepath)) != Z_OK) 31021300Sgjelinek goto done; 31031300Sgjelinek 31041300Sgjelinek /* 31051300Sgjelinek * We have to set the state of the zone to installed so that we 31061300Sgjelinek * can boot it and sys-unconfig it from within the zone. However, 31071300Sgjelinek * if something fails during the boot/sys-unconfig, we want to set 31081300Sgjelinek * the state back to incomplete. We use the revert flag to keep 31091300Sgjelinek * track of this. 31101300Sgjelinek */ 31111300Sgjelinek revert = B_TRUE; 31121300Sgjelinek 31131300Sgjelinek if ((err = zone_set_state(target_zone, ZONE_STATE_INSTALLED)) != Z_OK) { 31141300Sgjelinek errno = err; 31151300Sgjelinek zperror2(target_zone, gettext("\ncould not set state")); 31161300Sgjelinek goto done; 31171300Sgjelinek } 31181300Sgjelinek 31191300Sgjelinek /* 31201300Sgjelinek * Check if the zone is already sys-unconfiged. This saves us 31211300Sgjelinek * the work of booting the zone so we can unconfigure it. 31221300Sgjelinek */ 31231300Sgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), "%s/root/etc/.UNCONFIGURED", 31241300Sgjelinek zonepath); 31251300Sgjelinek if (stat(cmdbuf, &unconfig_buf) == -1) { 31261300Sgjelinek if ((err = boot_func(1, boot_args)) != Z_OK) { 31271300Sgjelinek errno = err; 31281300Sgjelinek zperror2(target_zone, gettext("\nCould not boot zone " 31291300Sgjelinek "for sys-unconfig\n")); 31301300Sgjelinek goto done; 31311300Sgjelinek } 31321300Sgjelinek 31331300Sgjelinek if ((err = zone_wait_single_user()) != Z_OK) { 31341300Sgjelinek errno = err; 31351300Sgjelinek zperror2(target_zone, gettext("\nCould not boot zone " 31361300Sgjelinek "for sys-unconfig\n")); 31371300Sgjelinek (void) halt_func(0, halt_args); 31381300Sgjelinek goto done; 31391300Sgjelinek } 31401300Sgjelinek 31411300Sgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), 31421300Sgjelinek "echo y | /usr/sbin/zlogin -S %s /usr/sbin/sys-unconfig", 31431300Sgjelinek target_zone); 31441300Sgjelinek 31451300Sgjelinek status = do_subproc(cmdbuf); 31461300Sgjelinek if ((err = subproc_status("sys-unconfig", status)) != Z_OK) { 31471300Sgjelinek errno = err; 31481300Sgjelinek zperror2(target_zone, 31491300Sgjelinek gettext("\nsys-unconfig failed\n")); 31501300Sgjelinek /* 31511300Sgjelinek * The sys-unconfig halts the zone but if it failed, 31521300Sgjelinek * for some reason, we'll try to halt it now. 31531300Sgjelinek */ 31541300Sgjelinek (void) halt_func(0, halt_args); 31551300Sgjelinek goto done; 31561300Sgjelinek } 31571300Sgjelinek } 31581300Sgjelinek 31591300Sgjelinek revert = B_FALSE; 31601300Sgjelinek 31611300Sgjelinek done: 31621300Sgjelinek (void) printf("\n"); 31631300Sgjelinek 31641300Sgjelinek if (revert) 31651300Sgjelinek (void) zone_set_state(target_zone, ZONE_STATE_INCOMPLETE); 31661300Sgjelinek 31671300Sgjelinek release_lock_file(lockfd); 31681300Sgjelinek return ((err == Z_OK) ? Z_OK : Z_ERR); 31691300Sgjelinek } 31701300Sgjelinek 31711300Sgjelinek #define RMCOMMAND "/usr/bin/rm -rf" 31721300Sgjelinek 31731300Sgjelinek static int 31741300Sgjelinek move_func(int argc, char *argv[]) 31751300Sgjelinek { 31761300Sgjelinek /* 6: "exec " and " " */ 31771300Sgjelinek char cmdbuf[sizeof (RMCOMMAND) + MAXPATHLEN + 6]; 31781300Sgjelinek char *new_zonepath = NULL; 31791300Sgjelinek int lockfd; 31801300Sgjelinek int err, arg; 31811300Sgjelinek char zonepath[MAXPATHLEN]; 31821300Sgjelinek zone_dochandle_t handle; 31831300Sgjelinek boolean_t fast; 31841300Sgjelinek boolean_t revert; 31851300Sgjelinek struct stat zonepath_buf; 31861300Sgjelinek struct stat new_zonepath_buf; 31871300Sgjelinek 31881300Sgjelinek if (zonecfg_in_alt_root()) { 31891300Sgjelinek zerror(gettext("cannot move zone in alternate root")); 31901300Sgjelinek return (Z_ERR); 31911300Sgjelinek } 31921300Sgjelinek 31931300Sgjelinek optind = 0; 31941300Sgjelinek if ((arg = getopt(argc, argv, "?")) != EOF) { 31951300Sgjelinek switch (arg) { 31961300Sgjelinek case '?': 31971300Sgjelinek sub_usage(SHELP_MOVE, CMD_MOVE); 31981300Sgjelinek return (optopt == '?' ? Z_OK : Z_USAGE); 31991300Sgjelinek default: 32001300Sgjelinek sub_usage(SHELP_MOVE, CMD_MOVE); 32011300Sgjelinek return (Z_USAGE); 32021300Sgjelinek } 32031300Sgjelinek } 32041300Sgjelinek if (argc != (optind + 1)) { 32051300Sgjelinek sub_usage(SHELP_MOVE, CMD_MOVE); 32061300Sgjelinek return (Z_USAGE); 32071300Sgjelinek } 32081300Sgjelinek new_zonepath = argv[optind]; 32091300Sgjelinek if (sanity_check(target_zone, CMD_MOVE, B_FALSE, B_TRUE) != Z_OK) 32101300Sgjelinek return (Z_ERR); 32111300Sgjelinek if (verify_details(CMD_MOVE) != Z_OK) 32121300Sgjelinek return (Z_ERR); 32131300Sgjelinek 32141300Sgjelinek /* 32151300Sgjelinek * Check out the new zonepath. This has the side effect of creating 32161300Sgjelinek * a directory for the new zonepath. We depend on this later when we 32171300Sgjelinek * stat to see if we are doing a cross file-system move or not. 32181300Sgjelinek */ 32191300Sgjelinek if (validate_zonepath(new_zonepath, CMD_MOVE) != Z_OK) 32201300Sgjelinek return (Z_ERR); 32211300Sgjelinek 32221300Sgjelinek if ((err = zone_get_zonepath(target_zone, zonepath, sizeof (zonepath))) 32231300Sgjelinek != Z_OK) { 32241300Sgjelinek errno = err; 32251300Sgjelinek zperror2(target_zone, gettext("could not get zone path")); 32261300Sgjelinek return (Z_ERR); 32271300Sgjelinek } 32281300Sgjelinek 32291300Sgjelinek if (stat(zonepath, &zonepath_buf) == -1) { 32301300Sgjelinek zperror(gettext("could not stat zone path"), B_FALSE); 32311300Sgjelinek return (Z_ERR); 32321300Sgjelinek } 32331300Sgjelinek 32341300Sgjelinek if (stat(new_zonepath, &new_zonepath_buf) == -1) { 32351300Sgjelinek zperror(gettext("could not stat new zone path"), B_FALSE); 32361300Sgjelinek return (Z_ERR); 32371300Sgjelinek } 32381300Sgjelinek 32391300Sgjelinek /* Don't move the zone if anything is still mounted there */ 32401300Sgjelinek if (zonecfg_find_mounts(zonepath, NULL, NULL)) { 32411300Sgjelinek zerror(gettext("These file-systems are mounted on " 32421300Sgjelinek "subdirectories of %s.\n"), zonepath); 32431300Sgjelinek (void) zonecfg_find_mounts(zonepath, zfm_print, NULL); 32441300Sgjelinek return (Z_ERR); 32451300Sgjelinek } 32461300Sgjelinek 32471300Sgjelinek /* 32481300Sgjelinek * Check if we are moving in the same filesystem and can do a fast 32491300Sgjelinek * move or if we are crossing filesystems and have to copy the data. 32501300Sgjelinek */ 32511300Sgjelinek fast = (zonepath_buf.st_dev == new_zonepath_buf.st_dev); 32521300Sgjelinek 32531300Sgjelinek if ((handle = zonecfg_init_handle()) == NULL) { 32541300Sgjelinek zperror(cmd_to_str(CMD_MOVE), B_TRUE); 32551300Sgjelinek return (Z_ERR); 32561300Sgjelinek } 32571300Sgjelinek 32581300Sgjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) { 32591300Sgjelinek errno = err; 32601300Sgjelinek zperror(cmd_to_str(CMD_MOVE), B_TRUE); 32611300Sgjelinek zonecfg_fini_handle(handle); 32621300Sgjelinek return (Z_ERR); 32631300Sgjelinek } 32641300Sgjelinek 32651300Sgjelinek if (grab_lock_file(target_zone, &lockfd) != Z_OK) { 32661300Sgjelinek zerror(gettext("another %s may have an operation in progress."), 32671300Sgjelinek "zoneadm"); 32681300Sgjelinek zonecfg_fini_handle(handle); 32691300Sgjelinek return (Z_ERR); 32701300Sgjelinek } 32711300Sgjelinek 32721300Sgjelinek /* 32731300Sgjelinek * We're making some file-system changes now so we have to clean up 32741300Sgjelinek * the file-system before we are done. This will either clean up the 32751300Sgjelinek * new zonepath if the zonecfg update failed or it will clean up the 32761300Sgjelinek * old zonepath if everything is ok. 32771300Sgjelinek */ 32781300Sgjelinek revert = B_TRUE; 32791300Sgjelinek 32801300Sgjelinek if (fast) { 32811300Sgjelinek /* same filesystem, use rename for a quick move */ 32821300Sgjelinek 32831300Sgjelinek /* 32841300Sgjelinek * Remove the new_zonepath directory that got created above 32851300Sgjelinek * during the validation. It gets in the way of the rename. 32861300Sgjelinek */ 32871300Sgjelinek if (rmdir(new_zonepath) != 0) { 32881300Sgjelinek zperror(gettext("could not rmdir new zone path"), 32891300Sgjelinek B_FALSE); 32901300Sgjelinek zonecfg_fini_handle(handle); 32911300Sgjelinek release_lock_file(lockfd); 32921300Sgjelinek return (Z_ERR); 32931300Sgjelinek } 32941300Sgjelinek 32951300Sgjelinek if (rename(zonepath, new_zonepath) != 0) { 32961300Sgjelinek /* 32971300Sgjelinek * If this fails we don't need to do all of the 32981300Sgjelinek * cleanup that happens for the rest of the code 32991300Sgjelinek * so just return from this error. 33001300Sgjelinek */ 33011300Sgjelinek zperror(gettext("could not move zone"), B_FALSE); 33021300Sgjelinek zonecfg_fini_handle(handle); 33031300Sgjelinek release_lock_file(lockfd); 33041300Sgjelinek return (Z_ERR); 33051300Sgjelinek } 33061300Sgjelinek 33071300Sgjelinek } else { 33081300Sgjelinek (void) printf(gettext( 33091300Sgjelinek "Moving across file-systems; copying zonepath %s..."), 33101300Sgjelinek zonepath); 33111300Sgjelinek (void) fflush(stdout); 33121300Sgjelinek 33131300Sgjelinek err = copy_zone(zonepath, new_zonepath); 33141300Sgjelinek 33151300Sgjelinek (void) printf("\n"); 33161300Sgjelinek if (err != Z_OK) 33171300Sgjelinek goto done; 33181300Sgjelinek } 33191300Sgjelinek 33201300Sgjelinek if ((err = zonecfg_set_zonepath(handle, new_zonepath)) != Z_OK) { 33211300Sgjelinek errno = err; 33221300Sgjelinek zperror(gettext("could not set new zonepath"), B_TRUE); 33231300Sgjelinek goto done; 33241300Sgjelinek } 33251300Sgjelinek 33261300Sgjelinek if ((err = zonecfg_save(handle)) != Z_OK) { 33271300Sgjelinek errno = err; 33281300Sgjelinek zperror(gettext("zonecfg save failed"), B_TRUE); 33291300Sgjelinek goto done; 33301300Sgjelinek } 33311300Sgjelinek 33321300Sgjelinek revert = B_FALSE; 33331300Sgjelinek 33341300Sgjelinek done: 33351300Sgjelinek zonecfg_fini_handle(handle); 33361300Sgjelinek release_lock_file(lockfd); 33371300Sgjelinek 33381300Sgjelinek /* 33391300Sgjelinek * Clean up the file-system based on how things went. We either 33401300Sgjelinek * clean up the new zonepath if the operation failed for some reason 33411300Sgjelinek * or we clean up the old zonepath if everything is ok. 33421300Sgjelinek */ 33431300Sgjelinek if (revert) { 33441300Sgjelinek /* The zonecfg update failed, cleanup the new zonepath. */ 33451300Sgjelinek if (fast) { 33461300Sgjelinek if (rename(new_zonepath, zonepath) != 0) { 33471300Sgjelinek zperror(gettext("could not restore zonepath"), 33481300Sgjelinek B_FALSE); 33491300Sgjelinek /* 33501300Sgjelinek * err is already != Z_OK since we're reverting 33511300Sgjelinek */ 33521300Sgjelinek } 33531300Sgjelinek } else { 33541300Sgjelinek int status; 33551300Sgjelinek 33561300Sgjelinek (void) printf(gettext("Cleaning up zonepath %s..."), 33571300Sgjelinek new_zonepath); 33581300Sgjelinek (void) fflush(stdout); 33591300Sgjelinek 33601300Sgjelinek /* 33611300Sgjelinek * "exec" the command so that the returned status is 33621300Sgjelinek * that of rm and not the shell. 33631300Sgjelinek */ 33641300Sgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), 33651300Sgjelinek "exec " RMCOMMAND " %s", new_zonepath); 33661300Sgjelinek 33671300Sgjelinek status = do_subproc(cmdbuf); 33681300Sgjelinek 33691300Sgjelinek (void) printf("\n"); 33701300Sgjelinek 33711300Sgjelinek if ((err = subproc_status("rm", status)) != Z_OK) { 33721300Sgjelinek errno = err; 33731300Sgjelinek zperror(gettext("could not remove new " 33741300Sgjelinek "zonepath"), B_TRUE); 33751300Sgjelinek } else { 33761300Sgjelinek /* 33771300Sgjelinek * Because we're reverting we know the mainline 33781300Sgjelinek * code failed but we just reused the err 33791300Sgjelinek * variable so we reset it back to Z_ERR. 33801300Sgjelinek */ 33811300Sgjelinek err = Z_ERR; 33821300Sgjelinek } 33831300Sgjelinek } 33841300Sgjelinek 33851300Sgjelinek } else { 33861300Sgjelinek /* The move was successful, cleanup the old zonepath. */ 33871300Sgjelinek if (!fast) { 33881300Sgjelinek int status; 33891300Sgjelinek 33901300Sgjelinek (void) printf( 33911300Sgjelinek gettext("Cleaning up zonepath %s..."), zonepath); 33921300Sgjelinek (void) fflush(stdout); 33931300Sgjelinek 33941300Sgjelinek /* 33951300Sgjelinek * "exec" the command so that the returned status is 33961300Sgjelinek * that of rm and not the shell. 33971300Sgjelinek */ 33981300Sgjelinek (void) snprintf(cmdbuf, sizeof (cmdbuf), 33991300Sgjelinek "exec " RMCOMMAND " %s", zonepath); 34001300Sgjelinek 34011300Sgjelinek status = do_subproc(cmdbuf); 34021300Sgjelinek 34031300Sgjelinek (void) printf("\n"); 34041300Sgjelinek 34051300Sgjelinek if ((err = subproc_status("rm", status)) != Z_OK) { 34061300Sgjelinek errno = err; 34071300Sgjelinek zperror(gettext("could not remove zonepath"), 34081300Sgjelinek B_TRUE); 34091300Sgjelinek } 34101300Sgjelinek } 34111300Sgjelinek } 34121300Sgjelinek 34131300Sgjelinek return ((err == Z_OK) ? Z_OK : Z_ERR); 34141300Sgjelinek } 34151300Sgjelinek 34161300Sgjelinek /* 34170Sstevel@tonic-gate * On input, TRUE => yes, FALSE => no. 34180Sstevel@tonic-gate * On return, TRUE => 1, FALSE => 0, could not ask => -1. 34190Sstevel@tonic-gate */ 34200Sstevel@tonic-gate 34210Sstevel@tonic-gate static int 34220Sstevel@tonic-gate ask_yesno(boolean_t default_answer, const char *question) 34230Sstevel@tonic-gate { 34240Sstevel@tonic-gate char line[64]; /* should be large enough to answer yes or no */ 34250Sstevel@tonic-gate 34260Sstevel@tonic-gate if (!isatty(STDIN_FILENO)) 34270Sstevel@tonic-gate return (-1); 34280Sstevel@tonic-gate for (;;) { 34290Sstevel@tonic-gate (void) printf("%s (%s)? ", question, 34300Sstevel@tonic-gate default_answer ? "[y]/n" : "y/[n]"); 34310Sstevel@tonic-gate if (fgets(line, sizeof (line), stdin) == NULL || 34320Sstevel@tonic-gate line[0] == '\n') 34330Sstevel@tonic-gate return (default_answer ? 1 : 0); 34340Sstevel@tonic-gate if (tolower(line[0]) == 'y') 34350Sstevel@tonic-gate return (1); 34360Sstevel@tonic-gate if (tolower(line[0]) == 'n') 34370Sstevel@tonic-gate return (0); 34380Sstevel@tonic-gate } 34390Sstevel@tonic-gate } 34400Sstevel@tonic-gate 34410Sstevel@tonic-gate static int 34420Sstevel@tonic-gate uninstall_func(int argc, char *argv[]) 34430Sstevel@tonic-gate { 34440Sstevel@tonic-gate /* 6: "exec " and " " */ 34450Sstevel@tonic-gate char cmdbuf[sizeof (RMCOMMAND) + MAXPATHLEN + 6]; 34460Sstevel@tonic-gate char line[ZONENAME_MAX + 128]; /* Enough for "Are you sure ..." */ 34470Sstevel@tonic-gate char rootpath[MAXPATHLEN], devpath[MAXPATHLEN]; 34480Sstevel@tonic-gate boolean_t force = B_FALSE; 34490Sstevel@tonic-gate int lockfd, answer; 34500Sstevel@tonic-gate int err, arg; 34510Sstevel@tonic-gate int status; 34520Sstevel@tonic-gate 3453766Scarlsonj if (zonecfg_in_alt_root()) { 3454766Scarlsonj zerror(gettext("cannot uninstall zone in alternate root")); 3455766Scarlsonj return (Z_ERR); 3456766Scarlsonj } 3457766Scarlsonj 34580Sstevel@tonic-gate optind = 0; 34590Sstevel@tonic-gate while ((arg = getopt(argc, argv, "?F")) != EOF) { 34600Sstevel@tonic-gate switch (arg) { 34610Sstevel@tonic-gate case '?': 34620Sstevel@tonic-gate sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL); 34630Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 34640Sstevel@tonic-gate case 'F': 34650Sstevel@tonic-gate force = B_TRUE; 34660Sstevel@tonic-gate break; 34670Sstevel@tonic-gate default: 34680Sstevel@tonic-gate sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL); 34690Sstevel@tonic-gate return (Z_USAGE); 34700Sstevel@tonic-gate } 34710Sstevel@tonic-gate } 34720Sstevel@tonic-gate if (argc > optind) { 34730Sstevel@tonic-gate sub_usage(SHELP_UNINSTALL, CMD_UNINSTALL); 34740Sstevel@tonic-gate return (Z_USAGE); 34750Sstevel@tonic-gate } 34760Sstevel@tonic-gate 34770Sstevel@tonic-gate if (sanity_check(target_zone, CMD_UNINSTALL, B_FALSE, B_TRUE) != Z_OK) 34780Sstevel@tonic-gate return (Z_ERR); 34790Sstevel@tonic-gate 34800Sstevel@tonic-gate if (!force) { 34810Sstevel@tonic-gate (void) snprintf(line, sizeof (line), 34820Sstevel@tonic-gate gettext("Are you sure you want to %s zone %s"), 34830Sstevel@tonic-gate cmd_to_str(CMD_UNINSTALL), target_zone); 34840Sstevel@tonic-gate if ((answer = ask_yesno(B_FALSE, line)) == 0) { 34850Sstevel@tonic-gate return (Z_OK); 34860Sstevel@tonic-gate } else if (answer == -1) { 34870Sstevel@tonic-gate zerror(gettext("Input not from terminal and -F " 34880Sstevel@tonic-gate "not specified: %s not done."), 34890Sstevel@tonic-gate cmd_to_str(CMD_UNINSTALL)); 34900Sstevel@tonic-gate return (Z_ERR); 34910Sstevel@tonic-gate } 34920Sstevel@tonic-gate } 34930Sstevel@tonic-gate 34940Sstevel@tonic-gate if ((err = zone_get_zonepath(target_zone, devpath, 34950Sstevel@tonic-gate sizeof (devpath))) != Z_OK) { 34960Sstevel@tonic-gate errno = err; 34970Sstevel@tonic-gate zperror2(target_zone, gettext("could not get zone path")); 34980Sstevel@tonic-gate return (Z_ERR); 34990Sstevel@tonic-gate } 35000Sstevel@tonic-gate (void) strlcat(devpath, "/dev", sizeof (devpath)); 35010Sstevel@tonic-gate if ((err = zone_get_rootpath(target_zone, rootpath, 35020Sstevel@tonic-gate sizeof (rootpath))) != Z_OK) { 35030Sstevel@tonic-gate errno = err; 35040Sstevel@tonic-gate zperror2(target_zone, gettext("could not get root path")); 35050Sstevel@tonic-gate return (Z_ERR); 35060Sstevel@tonic-gate } 35070Sstevel@tonic-gate 35080Sstevel@tonic-gate /* 35090Sstevel@tonic-gate * If there seems to be a zoneadmd running for this zone, call it 35100Sstevel@tonic-gate * to tell it that an uninstall is happening; if all goes well it 35110Sstevel@tonic-gate * will then shut itself down. 35120Sstevel@tonic-gate */ 35130Sstevel@tonic-gate if (ping_zoneadmd(target_zone) == Z_OK) { 35140Sstevel@tonic-gate zone_cmd_arg_t zarg; 35150Sstevel@tonic-gate zarg.cmd = Z_NOTE_UNINSTALLING; 35160Sstevel@tonic-gate /* we don't care too much if this fails... just plow on */ 35170Sstevel@tonic-gate (void) call_zoneadmd(target_zone, &zarg); 35180Sstevel@tonic-gate } 35190Sstevel@tonic-gate 35200Sstevel@tonic-gate if (grab_lock_file(target_zone, &lockfd) != Z_OK) { 35210Sstevel@tonic-gate zerror(gettext("another %s may have an operation in progress."), 35221300Sgjelinek "zoneadm"); 35230Sstevel@tonic-gate return (Z_ERR); 35240Sstevel@tonic-gate } 35250Sstevel@tonic-gate 35260Sstevel@tonic-gate /* Don't uninstall the zone if anything is mounted there */ 35270Sstevel@tonic-gate err = zonecfg_find_mounts(rootpath, NULL, NULL); 35280Sstevel@tonic-gate if (err) { 35290Sstevel@tonic-gate zerror(gettext("These file-systems are mounted on " 35300Sstevel@tonic-gate "subdirectories of %s.\n"), rootpath); 35310Sstevel@tonic-gate (void) zonecfg_find_mounts(rootpath, zfm_print, NULL); 35320Sstevel@tonic-gate return (Z_ERR); 35330Sstevel@tonic-gate } 35340Sstevel@tonic-gate 35350Sstevel@tonic-gate err = zone_set_state(target_zone, ZONE_STATE_INCOMPLETE); 35360Sstevel@tonic-gate if (err != Z_OK) { 35370Sstevel@tonic-gate errno = err; 35380Sstevel@tonic-gate zperror2(target_zone, gettext("could not set state")); 35390Sstevel@tonic-gate goto bad; 35400Sstevel@tonic-gate } 35410Sstevel@tonic-gate 35420Sstevel@tonic-gate /* 35430Sstevel@tonic-gate * "exec" the command so that the returned status is that of 35440Sstevel@tonic-gate * RMCOMMAND and not the shell. 35450Sstevel@tonic-gate */ 35460Sstevel@tonic-gate (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s", 35470Sstevel@tonic-gate devpath); 35480Sstevel@tonic-gate status = do_subproc(cmdbuf); 35490Sstevel@tonic-gate if ((err = subproc_status(RMCOMMAND, status)) != Z_OK) 35500Sstevel@tonic-gate goto bad; 35510Sstevel@tonic-gate (void) snprintf(cmdbuf, sizeof (cmdbuf), "exec " RMCOMMAND " %s", 35520Sstevel@tonic-gate rootpath); 35530Sstevel@tonic-gate status = do_subproc(cmdbuf); 35540Sstevel@tonic-gate if ((err = subproc_status(RMCOMMAND, status)) != Z_OK) 35550Sstevel@tonic-gate goto bad; 35560Sstevel@tonic-gate err = zone_set_state(target_zone, ZONE_STATE_CONFIGURED); 35570Sstevel@tonic-gate if (err != Z_OK) { 35580Sstevel@tonic-gate errno = err; 35590Sstevel@tonic-gate zperror2(target_zone, gettext("could not reset state")); 35600Sstevel@tonic-gate } 35610Sstevel@tonic-gate bad: 35620Sstevel@tonic-gate release_lock_file(lockfd); 35630Sstevel@tonic-gate return (err); 35640Sstevel@tonic-gate } 35650Sstevel@tonic-gate 3566766Scarlsonj /* ARGSUSED */ 3567766Scarlsonj static int 3568766Scarlsonj mount_func(int argc, char *argv[]) 3569766Scarlsonj { 3570766Scarlsonj zone_cmd_arg_t zarg; 3571766Scarlsonj 3572766Scarlsonj if (argc > 0) 3573766Scarlsonj return (Z_USAGE); 3574766Scarlsonj if (sanity_check(target_zone, CMD_MOUNT, B_FALSE, B_FALSE) != Z_OK) 3575766Scarlsonj return (Z_ERR); 3576766Scarlsonj if (verify_details(CMD_MOUNT) != Z_OK) 3577766Scarlsonj return (Z_ERR); 3578766Scarlsonj 3579766Scarlsonj zarg.cmd = Z_MOUNT; 3580766Scarlsonj if (call_zoneadmd(target_zone, &zarg) != 0) { 3581766Scarlsonj zerror(gettext("call to %s failed"), "zoneadmd"); 3582766Scarlsonj return (Z_ERR); 3583766Scarlsonj } 3584766Scarlsonj return (Z_OK); 3585766Scarlsonj } 3586766Scarlsonj 3587766Scarlsonj /* ARGSUSED */ 3588766Scarlsonj static int 3589766Scarlsonj unmount_func(int argc, char *argv[]) 3590766Scarlsonj { 3591766Scarlsonj zone_cmd_arg_t zarg; 3592766Scarlsonj 3593766Scarlsonj if (argc > 0) 3594766Scarlsonj return (Z_USAGE); 3595766Scarlsonj if (sanity_check(target_zone, CMD_UNMOUNT, B_FALSE, B_FALSE) != Z_OK) 3596766Scarlsonj return (Z_ERR); 3597766Scarlsonj 3598766Scarlsonj zarg.cmd = Z_UNMOUNT; 3599766Scarlsonj if (call_zoneadmd(target_zone, &zarg) != 0) { 3600766Scarlsonj zerror(gettext("call to %s failed"), "zoneadmd"); 3601766Scarlsonj return (Z_ERR); 3602766Scarlsonj } 3603766Scarlsonj return (Z_OK); 3604766Scarlsonj } 3605766Scarlsonj 36060Sstevel@tonic-gate static int 36070Sstevel@tonic-gate help_func(int argc, char *argv[]) 36080Sstevel@tonic-gate { 36090Sstevel@tonic-gate int arg, cmd_num; 36100Sstevel@tonic-gate 36110Sstevel@tonic-gate if (argc == 0) { 36120Sstevel@tonic-gate (void) usage(B_TRUE); 36130Sstevel@tonic-gate return (Z_OK); 36140Sstevel@tonic-gate } 36150Sstevel@tonic-gate optind = 0; 36160Sstevel@tonic-gate if ((arg = getopt(argc, argv, "?")) != EOF) { 36170Sstevel@tonic-gate switch (arg) { 36180Sstevel@tonic-gate case '?': 36190Sstevel@tonic-gate sub_usage(SHELP_HELP, CMD_HELP); 36200Sstevel@tonic-gate return (optopt == '?' ? Z_OK : Z_USAGE); 36210Sstevel@tonic-gate default: 36220Sstevel@tonic-gate sub_usage(SHELP_HELP, CMD_HELP); 36230Sstevel@tonic-gate return (Z_USAGE); 36240Sstevel@tonic-gate } 36250Sstevel@tonic-gate } 36260Sstevel@tonic-gate while (optind < argc) { 3627988Scarlsonj /* Private commands have NULL short_usage; omit them */ 3628988Scarlsonj if ((cmd_num = cmd_match(argv[optind])) < 0 || 3629988Scarlsonj cmdtab[cmd_num].short_usage == NULL) { 36300Sstevel@tonic-gate sub_usage(SHELP_HELP, CMD_HELP); 36310Sstevel@tonic-gate return (Z_USAGE); 36320Sstevel@tonic-gate } 36330Sstevel@tonic-gate sub_usage(cmdtab[cmd_num].short_usage, cmd_num); 36340Sstevel@tonic-gate optind++; 36350Sstevel@tonic-gate } 36360Sstevel@tonic-gate return (Z_OK); 36370Sstevel@tonic-gate } 36380Sstevel@tonic-gate 36390Sstevel@tonic-gate /* 36400Sstevel@tonic-gate * Returns: CMD_MIN thru CMD_MAX on success, -1 on error 36410Sstevel@tonic-gate */ 36420Sstevel@tonic-gate 36430Sstevel@tonic-gate static int 36440Sstevel@tonic-gate cmd_match(char *cmd) 36450Sstevel@tonic-gate { 36460Sstevel@tonic-gate int i; 36470Sstevel@tonic-gate 36480Sstevel@tonic-gate for (i = CMD_MIN; i <= CMD_MAX; i++) { 36490Sstevel@tonic-gate /* return only if there is an exact match */ 36500Sstevel@tonic-gate if (strcmp(cmd, cmdtab[i].cmd_name) == 0) 36510Sstevel@tonic-gate return (cmdtab[i].cmd_num); 36520Sstevel@tonic-gate } 36530Sstevel@tonic-gate return (-1); 36540Sstevel@tonic-gate } 36550Sstevel@tonic-gate 36560Sstevel@tonic-gate static int 36570Sstevel@tonic-gate parse_and_run(int argc, char *argv[]) 36580Sstevel@tonic-gate { 36590Sstevel@tonic-gate int i = cmd_match(argv[0]); 36600Sstevel@tonic-gate 36610Sstevel@tonic-gate if (i < 0) 36620Sstevel@tonic-gate return (usage(B_FALSE)); 36630Sstevel@tonic-gate return (cmdtab[i].handler(argc - 1, &(argv[1]))); 36640Sstevel@tonic-gate } 36650Sstevel@tonic-gate 36660Sstevel@tonic-gate static char * 36670Sstevel@tonic-gate get_execbasename(char *execfullname) 36680Sstevel@tonic-gate { 36690Sstevel@tonic-gate char *last_slash, *execbasename; 36700Sstevel@tonic-gate 36710Sstevel@tonic-gate /* guard against '/' at end of command invocation */ 36720Sstevel@tonic-gate for (;;) { 36730Sstevel@tonic-gate last_slash = strrchr(execfullname, '/'); 36740Sstevel@tonic-gate if (last_slash == NULL) { 36750Sstevel@tonic-gate execbasename = execfullname; 36760Sstevel@tonic-gate break; 36770Sstevel@tonic-gate } else { 36780Sstevel@tonic-gate execbasename = last_slash + 1; 36790Sstevel@tonic-gate if (*execbasename == '\0') { 36800Sstevel@tonic-gate *last_slash = '\0'; 36810Sstevel@tonic-gate continue; 36820Sstevel@tonic-gate } 36830Sstevel@tonic-gate break; 36840Sstevel@tonic-gate } 36850Sstevel@tonic-gate } 36860Sstevel@tonic-gate return (execbasename); 36870Sstevel@tonic-gate } 36880Sstevel@tonic-gate 36890Sstevel@tonic-gate int 36900Sstevel@tonic-gate main(int argc, char **argv) 36910Sstevel@tonic-gate { 36920Sstevel@tonic-gate int arg; 36930Sstevel@tonic-gate zoneid_t zid; 3694766Scarlsonj struct stat st; 36950Sstevel@tonic-gate 36960Sstevel@tonic-gate if ((locale = setlocale(LC_ALL, "")) == NULL) 36970Sstevel@tonic-gate locale = "C"; 36980Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 36990Sstevel@tonic-gate setbuf(stdout, NULL); 37000Sstevel@tonic-gate (void) sigset(SIGHUP, SIG_IGN); 37010Sstevel@tonic-gate execname = get_execbasename(argv[0]); 37020Sstevel@tonic-gate target_zone = NULL; 37030Sstevel@tonic-gate if (chdir("/") != 0) { 37040Sstevel@tonic-gate zerror(gettext("could not change directory to /.")); 37050Sstevel@tonic-gate exit(Z_ERR); 37060Sstevel@tonic-gate } 37070Sstevel@tonic-gate 3708766Scarlsonj while ((arg = getopt(argc, argv, "?z:R:")) != EOF) { 37090Sstevel@tonic-gate switch (arg) { 37100Sstevel@tonic-gate case '?': 37110Sstevel@tonic-gate return (usage(B_TRUE)); 37120Sstevel@tonic-gate case 'z': 37130Sstevel@tonic-gate target_zone = optarg; 37140Sstevel@tonic-gate break; 3715766Scarlsonj case 'R': /* private option for admin/install use */ 3716766Scarlsonj if (*optarg != '/') { 3717766Scarlsonj zerror(gettext("root path must be absolute.")); 3718766Scarlsonj exit(Z_ERR); 3719766Scarlsonj } 3720766Scarlsonj if (stat(optarg, &st) == -1 || !S_ISDIR(st.st_mode)) { 3721766Scarlsonj zerror( 3722766Scarlsonj gettext("root path must be a directory.")); 3723766Scarlsonj exit(Z_ERR); 3724766Scarlsonj } 3725766Scarlsonj zonecfg_set_root(optarg); 3726766Scarlsonj break; 37270Sstevel@tonic-gate default: 37280Sstevel@tonic-gate return (usage(B_FALSE)); 37290Sstevel@tonic-gate } 37300Sstevel@tonic-gate } 37310Sstevel@tonic-gate 37320Sstevel@tonic-gate if (optind >= argc) 37330Sstevel@tonic-gate return (usage(B_FALSE)); 37340Sstevel@tonic-gate if (target_zone != NULL && zone_get_id(target_zone, &zid) != 0) { 37350Sstevel@tonic-gate errno = Z_NO_ZONE; 37360Sstevel@tonic-gate zperror(target_zone, B_TRUE); 37370Sstevel@tonic-gate exit(Z_ERR); 37380Sstevel@tonic-gate } 37390Sstevel@tonic-gate return (parse_and_run(argc - optind, &argv[optind])); 37400Sstevel@tonic-gate } 3741