summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/cmd/zoneadm/svc-zones3
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.c82
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.h30
-rw-r--r--usr/src/cmd/zoneadm/zones.xml11
-rw-r--r--usr/src/cmd/zoneadmd/Makefile3
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.c151
-rw-r--r--usr/src/cmd/zoneadmd/zoneadmd.h5
-rw-r--r--usr/src/lib/brand/ipkg/zone/config.xml2
-rw-r--r--usr/src/lib/brand/labeled/zone/config.xml2
-rw-r--r--usr/src/lib/brand/solaris10/zone/config.xml2
-rw-r--r--usr/src/lib/libbrand/common/libbrand.c11
-rw-r--r--usr/src/lib/libbrand/common/libbrand.h3
-rw-r--r--usr/src/lib/libbrand/common/mapfile-vers2
-rw-r--r--usr/src/lib/libbrand/dtd/brand.dtd.129
-rw-r--r--usr/src/man/man1m/zoneadm.1m32
-rw-r--r--usr/src/uts/common/sys/zone.h3
16 files changed, 328 insertions, 43 deletions
diff --git a/usr/src/cmd/zoneadm/svc-zones b/usr/src/cmd/zoneadm/svc-zones
index 942a7ace27..9d307835bd 100644
--- a/usr/src/cmd/zoneadm/svc-zones
+++ b/usr/src/cmd/zoneadm/svc-zones
@@ -21,6 +21,7 @@
#
#
# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
. /lib/svc/share/smf_include.sh
@@ -109,7 +110,7 @@ case "$1" in
for zone in $zonelist; do
echo " $zone\c"
- zlogin -S $zone /sbin/init 0 < /dev/null >&0 2>&0 &
+ zoneadm -z $zone shutdown &
SHUTDOWN=1
done
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c
index d0305b48a8..2c25e18a53 100644
--- a/usr/src/cmd/zoneadm/zoneadm.c
+++ b/usr/src/cmd/zoneadm/zoneadm.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -130,6 +131,7 @@ struct cmd {
#define SHELP_BOOT "boot [-- boot_arguments]"
#define SHELP_HALT "halt"
#define SHELP_READY "ready"
+#define SHELP_SHUTDOWN "shutdown [-r [-- boot_arguments]]"
#define SHELP_REBOOT "reboot [-- boot_arguments]"
#define SHELP_LIST "list [-cipv]"
#define SHELP_VERIFY "verify"
@@ -152,6 +154,7 @@ static int cleanup_zonepath(char *, boolean_t);
static int help_func(int argc, char *argv[]);
static int ready_func(int argc, char *argv[]);
static int boot_func(int argc, char *argv[]);
+static int shutdown_func(int argc, char *argv[]);
static int halt_func(int argc, char *argv[]);
static int reboot_func(int argc, char *argv[]);
static int list_func(int argc, char *argv[]);
@@ -179,6 +182,7 @@ static struct cmd cmdtab[] = {
{ CMD_BOOT, "boot", SHELP_BOOT, boot_func },
{ CMD_HALT, "halt", SHELP_HALT, halt_func },
{ CMD_READY, "ready", SHELP_READY, ready_func },
+ { CMD_SHUTDOWN, "shutdown", SHELP_SHUTDOWN, shutdown_func },
{ CMD_REBOOT, "reboot", SHELP_REBOOT, reboot_func },
{ CMD_LIST, "list", SHELP_LIST, list_func },
{ CMD_VERIFY, "verify", SHELP_VERIFY, verify_func },
@@ -232,6 +236,10 @@ long_help(int cmd_num)
case CMD_READY:
return (gettext("Prepares a zone for running applications but "
"does not start any user\n\tprocesses in the zone."));
+ case CMD_SHUTDOWN:
+ return (gettext("Gracefully shutdown the zone or reboot if "
+ "the '-r' option is specified.\n\t"
+ "See zoneadm(1m) for valid boot arguments."));
case CMD_REBOOT:
return (gettext("Restarts the zone (equivalent to a halt / "
"boot sequence).\n\tFails if the zone is not active. "
@@ -1534,6 +1542,7 @@ auth_check(char *user, char *zone, int cmd_num)
case CMD_BOOT:
case CMD_HALT:
case CMD_READY:
+ case CMD_SHUTDOWN:
case CMD_REBOOT:
case CMD_SYSBOOT:
case CMD_VERIFY:
@@ -1596,6 +1605,10 @@ sanity_check(char *zone, int cmd_num, boolean_t running,
zerror(gettext("use %s to %s this zone."), "halt(1M)",
cmd_to_str(cmd_num));
break;
+ case CMD_SHUTDOWN:
+ zerror(gettext("use %s to %s this zone."),
+ "shutdown(1M)", cmd_to_str(cmd_num));
+ break;
case CMD_REBOOT:
zerror(gettext("use %s to %s this zone."),
"reboot(1M)", cmd_to_str(cmd_num));
@@ -1826,6 +1839,75 @@ halt_func(int argc, char *argv[])
}
static int
+shutdown_func(int argc, char *argv[])
+{
+ zone_cmd_arg_t zarg;
+ int arg;
+ boolean_t reboot = B_FALSE;
+
+ zarg.cmd = Z_SHUTDOWN;
+
+ if (zonecfg_in_alt_root()) {
+ zerror(gettext("cannot shut down zone in alternate root"));
+ return (Z_ERR);
+ }
+
+ optind = 0;
+ while ((arg = getopt(argc, argv, "?r")) != EOF) {
+ switch (arg) {
+ case '?':
+ sub_usage(SHELP_SHUTDOWN, CMD_SHUTDOWN);
+ return (optopt == '?' ? Z_OK : Z_USAGE);
+ case 'r':
+ reboot = B_TRUE;
+ break;
+ default:
+ sub_usage(SHELP_SHUTDOWN, CMD_SHUTDOWN);
+ return (Z_USAGE);
+ }
+ }
+
+ zarg.bootbuf[0] = '\0';
+ for (; optind < argc; optind++) {
+ if (strlcat(zarg.bootbuf, argv[optind],
+ sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) {
+ zerror(gettext("Boot argument list too long"));
+ return (Z_ERR);
+ }
+ if (optind < argc - 1)
+ if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >=
+ sizeof (zarg.bootbuf)) {
+ zerror(gettext("Boot argument list too long"));
+ return (Z_ERR);
+ }
+ }
+
+ /*
+ * zoneadmd should be the one to decide whether or not to proceed,
+ * so even though it seems that the third parameter below should
+ * perhaps be B_TRUE, it really shouldn't be.
+ */
+ if (sanity_check(target_zone, CMD_SHUTDOWN, B_TRUE, B_FALSE, B_FALSE)
+ != Z_OK)
+ return (Z_ERR);
+
+ if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != Z_OK)
+ return (Z_ERR);
+
+ if (reboot) {
+ if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE,
+ B_FALSE) != Z_OK)
+ return (Z_ERR);
+
+ zarg.cmd = Z_BOOT;
+ if (zonecfg_call_zoneadmd(target_zone, &zarg, locale,
+ B_TRUE) != Z_OK)
+ return (Z_ERR);
+ }
+ return (Z_OK);
+}
+
+static int
reboot_func(int argc, char *argv[])
{
zone_cmd_arg_t zarg;
diff --git a/usr/src/cmd/zoneadm/zoneadm.h b/usr/src/cmd/zoneadm/zoneadm.h
index 29c0b445ba..86db91a2c9 100644
--- a/usr/src/cmd/zoneadm/zoneadm.h
+++ b/usr/src/cmd/zoneadm/zoneadm.h
@@ -22,6 +22,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _ZONEADM_H
@@ -33,20 +34,21 @@
#define CMD_BOOT 1
#define CMD_HALT 2
#define CMD_READY 3
-#define CMD_REBOOT 4
-#define CMD_LIST 5
-#define CMD_VERIFY 6
-#define CMD_INSTALL 7
-#define CMD_UNINSTALL 8
-#define CMD_MOUNT 9
-#define CMD_UNMOUNT 10
-#define CMD_CLONE 11
-#define CMD_MOVE 12
-#define CMD_DETACH 13
-#define CMD_ATTACH 14
-#define CMD_MARK 15
-#define CMD_APPLY 16
-#define CMD_SYSBOOT 17
+#define CMD_SHUTDOWN 4
+#define CMD_REBOOT 5
+#define CMD_LIST 6
+#define CMD_VERIFY 7
+#define CMD_INSTALL 8
+#define CMD_UNINSTALL 9
+#define CMD_MOUNT 10
+#define CMD_UNMOUNT 11
+#define CMD_CLONE 12
+#define CMD_MOVE 13
+#define CMD_DETACH 14
+#define CMD_ATTACH 15
+#define CMD_MARK 16
+#define CMD_APPLY 17
+#define CMD_SYSBOOT 18
#define CMD_MIN CMD_HELP
#define CMD_MAX CMD_SYSBOOT
diff --git a/usr/src/cmd/zoneadm/zones.xml b/usr/src/cmd/zoneadm/zones.xml
index e14424ac26..9c8e305f89 100644
--- a/usr/src/cmd/zoneadm/zones.xml
+++ b/usr/src/cmd/zoneadm/zones.xml
@@ -23,12 +23,12 @@
CDDL HEADER END
- ident "%Z%%M% %I% %E% SMI"
-
NOTE: This service manifest is not editable; its contents will
be overwritten by package or patch operations, including
operating system upgrade. Make customizations in a different
file.
+
+ Copyright 2014 Nexenta Systems, Inc. All rights reserved.
-->
<service_bundle type='manifest' name='SUNWzoner:zones'>
@@ -64,10 +64,9 @@
<!--
The stop method reads the timeout_seconds property and
spends 3/4 of the allotted time waiting for zones to
- cleanly shut down (by running 'init 0' in each one). If
- some zones don't shutdown after the 3/4 time has elapsed,
- the method spends the remaining 1/4 trying to more forcibly
- halt the zones
+ cleanly shut down. If some zones don't shutdown after
+ the 3/4 time has elapsed, the method spends the remaining
+ 1/4 trying to more forcibly halt the zones
-->
<exec_method
type='method'
diff --git a/usr/src/cmd/zoneadmd/Makefile b/usr/src/cmd/zoneadmd/Makefile
index 078d6c7b39..8324f7fefa 100644
--- a/usr/src/cmd/zoneadmd/Makefile
+++ b/usr/src/cmd/zoneadmd/Makefile
@@ -23,6 +23,7 @@
#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
#
PROG= zoneadmd
@@ -43,7 +44,7 @@ CERRWARN += -_gcc=-Wno-uninitialized
LDLIBS += -lsocket -lzonecfg -lnsl -ldevinfo -ldevice -lnvpair \
-lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm -ltsnet -ltsol \
- -linetutil
+ -linetutil -lscf
XGETFLAGS += -a -x zoneadmd.xcl
.KEEP_STATE:
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.c b/usr/src/cmd/zoneadmd/zoneadmd.c
index 94ab464193..7a9d88410d 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.c
+++ b/usr/src/cmd/zoneadmd/zoneadmd.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -99,6 +100,7 @@
#include <sys/ctfs.h>
#include <libdladm.h>
#include <sys/dls_mgmt.h>
+#include <libscf.h>
#include <libzonecfg.h>
#include <zonestat_impl.h>
@@ -112,6 +114,7 @@ char brand_name[MAXNAMELEN];
boolean_t zone_isnative;
boolean_t zone_iscluster;
boolean_t zone_islabeled;
+boolean_t shutdown_in_progress;
static zoneid_t zone_id;
dladm_handle_t dld_handle = NULL;
@@ -144,7 +147,8 @@ z_cmd_name(zone_cmd_t zcmd)
/* This list needs to match the enum in sys/zone.h */
static const char *zcmdstr[] = {
"ready", "boot", "forceboot", "reboot", "halt",
- "note_uninstalling", "mount", "forcemount", "unmount"
+ "note_uninstalling", "mount", "forcemount", "unmount",
+ "shutdown"
};
if (zcmd >= sizeof (zcmdstr) / sizeof (*zcmdstr))
@@ -986,6 +990,133 @@ zone_halt(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting, int zstate)
return (0);
}
+static int
+zone_graceful_shutdown(zlog_t *zlogp)
+{
+ zoneid_t zoneid;
+ pid_t child;
+ char cmdbuf[MAXPATHLEN];
+ brand_handle_t bh = NULL;
+ char zpath[MAXPATHLEN];
+ ctid_t ct;
+ int tmpl_fd;
+ int child_status;
+
+ if (shutdown_in_progress) {
+ zerror(zlogp, B_FALSE, "shutdown already in progress");
+ return (-1);
+ }
+
+ if ((zoneid = getzoneidbyname(zone_name)) == -1) {
+ zerror(zlogp, B_TRUE, "unable to get zoneid");
+ return (-1);
+ }
+
+ /* Get a handle to the brand info for this zone */
+ if ((bh = brand_open(brand_name)) == NULL) {
+ zerror(zlogp, B_FALSE, "unable to determine zone brand");
+ return (-1);
+ }
+
+ if (zone_get_zonepath(zone_name, zpath, sizeof (zpath)) != Z_OK) {
+ zerror(zlogp, B_FALSE, "unable to determine zone path");
+ brand_close(bh);
+ return (-1);
+ }
+
+ /*
+ * If there is a brand 'shutdown' callback, execute it now to give the
+ * brand a chance to cleanup any custom configuration.
+ */
+ (void) strcpy(cmdbuf, EXEC_PREFIX);
+ if (brand_get_shutdown(bh, zone_name, zpath, cmdbuf + EXEC_LEN,
+ sizeof (cmdbuf) - EXEC_LEN) != 0 || strlen(cmdbuf) <= EXEC_LEN) {
+ (void) strcat(cmdbuf, SHUTDOWN_DEFAULT);
+ }
+ brand_close(bh);
+
+ if ((tmpl_fd = init_template()) == -1) {
+ zerror(zlogp, B_TRUE, "failed to create contract");
+ return (-1);
+ }
+
+ if ((child = fork()) == -1) {
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+ zerror(zlogp, B_TRUE, "failed to fork");
+ return (-1);
+ } else if (child == 0) {
+ (void) ct_tmpl_clear(tmpl_fd);
+ if (zone_enter(zoneid) == -1) {
+ _exit(errno);
+ }
+ _exit(execl("/bin/sh", "sh", "-c", cmdbuf, (char *)NULL));
+ }
+
+ if (contract_latest(&ct) == -1)
+ ct = -1;
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+
+ if (waitpid(child, &child_status, 0) != child) {
+ /* unexpected: we must have been signalled */
+ (void) contract_abandon_id(ct);
+ return (-1);
+ }
+
+ (void) contract_abandon_id(ct);
+ if (WEXITSTATUS(child_status) != 0) {
+ errno = WEXITSTATUS(child_status);
+ zerror(zlogp, B_FALSE, "unable to shutdown zone");
+ return (-1);
+ }
+
+ shutdown_in_progress = B_TRUE;
+
+ return (0);
+}
+
+static int
+zone_wait_shutdown(zlog_t *zlogp)
+{
+ zone_state_t zstate;
+ uint64_t *tm = NULL;
+ scf_simple_prop_t *prop = NULL;
+ int timeout;
+ int tries;
+ int rc = -1;
+
+ /* Get default stop timeout from SMF framework */
+ timeout = SHUTDOWN_WAIT;
+ if ((prop = scf_simple_prop_get(NULL, SHUTDOWN_FMRI, "stop",
+ SCF_PROPERTY_TIMEOUT)) != NULL) {
+ if ((tm = scf_simple_prop_next_count(prop)) != NULL) {
+ if (tm != 0)
+ timeout = *tm;
+ }
+ scf_simple_prop_free(prop);
+ }
+
+ /* allow time for zone to shutdown cleanly */
+ for (tries = 0; tries < timeout; tries ++) {
+ (void) sleep(1);
+ if (zone_get_state(zone_name, &zstate) == Z_OK &&
+ zstate == ZONE_STATE_INSTALLED) {
+ rc = 0;
+ break;
+ }
+ }
+
+ if (rc != 0)
+ zerror(zlogp, B_FALSE, "unable to shutdown zone");
+
+ shutdown_in_progress = B_FALSE;
+
+ return (rc);
+}
+
+
+
/*
* Generate AUE_zone_state for a command that boots a zone.
*/
@@ -1061,6 +1192,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
size_t rlen = getpagesize(); /* conservative */
fs_callback_t cb;
brand_handle_t bh;
+ boolean_t wait_shut = B_FALSE;
/* LINTED E_BAD_PTR_CAST_ALIGN */
zargp = (zone_cmd_arg_t *)args;
@@ -1137,8 +1269,9 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
* Check for validity of command.
*/
if (cmd != Z_READY && cmd != Z_BOOT && cmd != Z_FORCEBOOT &&
- cmd != Z_REBOOT && cmd != Z_HALT && cmd != Z_NOTE_UNINSTALLING &&
- cmd != Z_MOUNT && cmd != Z_FORCEMOUNT && cmd != Z_UNMOUNT) {
+ cmd != Z_REBOOT && cmd != Z_SHUTDOWN && cmd != Z_HALT &&
+ cmd != Z_NOTE_UNINSTALLING && cmd != Z_MOUNT &&
+ cmd != Z_FORCEMOUNT && cmd != Z_UNMOUNT) {
zerror(&logsys, B_FALSE, "invalid command %d", (int)cmd);
goto out;
}
@@ -1224,6 +1357,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
eventstream_write(Z_EVT_ZONE_BOOTFAILED);
}
break;
+ case Z_SHUTDOWN:
case Z_HALT:
if (kernelcall) /* Invalid; can't happen */
abort();
@@ -1354,6 +1488,7 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
break;
eventstream_write(Z_EVT_ZONE_HALTED);
break;
+ case Z_SHUTDOWN:
case Z_REBOOT:
case Z_NOTE_UNINSTALLING:
case Z_MOUNT:
@@ -1444,6 +1579,11 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
}
boot_args[0] = '\0';
break;
+ case Z_SHUTDOWN:
+ if ((rval = zone_graceful_shutdown(zlogp)) == 0) {
+ wait_shut = B_TRUE;
+ }
+ break;
case Z_NOTE_UNINSTALLING:
case Z_MOUNT:
case Z_UNMOUNT:
@@ -1467,6 +1607,11 @@ server(void *cookie, char *args, size_t alen, door_desc_t *dp,
out:
(void) mutex_unlock(&lock);
+
+ /* Wait for the Z_SHUTDOWN commands to complete */
+ if (wait_shut)
+ rval = zone_wait_shutdown(zlogp);
+
if (kernelcall) {
rvalp = NULL;
rlen = 0;
diff --git a/usr/src/cmd/zoneadmd/zoneadmd.h b/usr/src/cmd/zoneadmd/zoneadmd.h
index 63b23481d2..d784a303b3 100644
--- a/usr/src/cmd/zoneadmd/zoneadmd.h
+++ b/usr/src/cmd/zoneadmd/zoneadmd.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _ZONEADMD_H
@@ -58,6 +59,10 @@ extern "C" {
#define CLUSTER_BRAND_NAME "cluster"
#define LABELED_BRAND_NAME "labeled"
+#define SHUTDOWN_WAIT 60
+#define SHUTDOWN_DEFAULT "/sbin/init 0"
+#define SHUTDOWN_FMRI "svc:/system/zones:default"
+
/* 0755 is the default directory mode. */
#define DEFAULT_DIR_MODE \
(S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
diff --git a/usr/src/lib/brand/ipkg/zone/config.xml b/usr/src/lib/brand/ipkg/zone/config.xml
index 91f492bdde..e7307bfd8a 100644
--- a/usr/src/lib/brand/ipkg/zone/config.xml
+++ b/usr/src/lib/brand/ipkg/zone/config.xml
@@ -23,6 +23,7 @@
Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
DO NOT EDIT THIS FILE.
+ Copyright 2014 Nexenta Systems, Inc. All rights reserved.
-->
<!DOCTYPE brand PUBLIC "-//Sun Microsystems Inc//DTD Brands//EN"
@@ -42,6 +43,7 @@
<boot></boot>
<sysboot>/usr/lib/brand/ipkg/prestate %z %R 2 0</sysboot>
<halt></halt>
+ <shutdown>/usr/sbin/shutdown -y -g0 -i5</shutdown>
<verify_cfg></verify_cfg>
<verify_adm></verify_adm>
<postclone></postclone>
diff --git a/usr/src/lib/brand/labeled/zone/config.xml b/usr/src/lib/brand/labeled/zone/config.xml
index 1bad9a9a11..61db7bcbf3 100644
--- a/usr/src/lib/brand/labeled/zone/config.xml
+++ b/usr/src/lib/brand/labeled/zone/config.xml
@@ -23,6 +23,7 @@
Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
DO NOT EDIT THIS FILE.
+ Copyright 2014 Nexenta Systems, Inc. All rights reserved.
-->
<!DOCTYPE brand PUBLIC "-//Sun Microsystems Inc//DTD Brands//EN"
@@ -43,6 +44,7 @@
<boot></boot>
<sysboot>/usr/lib/brand/ipkg/prestate %z %R 2 0</sysboot>
<halt></halt>
+ <shutdown>/usr/sbin/shutdown -y -g0 -i5</shutdown>
<verify_cfg></verify_cfg>
<verify_adm></verify_adm>
<postclone></postclone>
diff --git a/usr/src/lib/brand/solaris10/zone/config.xml b/usr/src/lib/brand/solaris10/zone/config.xml
index e1bd2b64b0..a0eeaa0c98 100644
--- a/usr/src/lib/brand/solaris10/zone/config.xml
+++ b/usr/src/lib/brand/solaris10/zone/config.xml
@@ -23,6 +23,7 @@
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
DO NOT EDIT THIS FILE.
+ Copyright 2014 Nexenta Systems, Inc. All rights reserved.
-->
<!DOCTYPE brand PUBLIC "-//Sun Microsystems Inc//DTD Brands//EN"
@@ -40,6 +41,7 @@
<boot>/usr/lib/brand/solaris10/s10_boot %z %R</boot>
<sysboot>/usr/lib/brand/solaris10/prestate %z %R 2 0</sysboot>
<halt></halt>
+ <shutdown>/usr/sbin/shutdown -y -g0 -i5</shutdown>
<verify_cfg>/usr/lib/brand/solaris10/s10_support verify</verify_cfg>
<verify_adm></verify_adm>
<postattach>/usr/lib/brand/solaris10/postattach %z %R</postattach>
diff --git a/usr/src/lib/libbrand/common/libbrand.c b/usr/src/lib/libbrand/common/libbrand.c
index 5034715a7e..6cbc90eb59 100644
--- a/usr/src/lib/libbrand/common/libbrand.c
+++ b/usr/src/lib/libbrand/common/libbrand.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#include <assert.h>
@@ -71,6 +72,7 @@
#define DTD_ELEM_PREUNINSTALL ((const xmlChar *) "preuninstall")
#define DTD_ELEM_PRIVILEGE ((const xmlChar *) "privilege")
#define DTD_ELEM_QUERY ((const xmlChar *) "query")
+#define DTD_ELEM_SHUTDOWN ((const xmlChar *) "shutdown")
#define DTD_ELEM_SYMLINK ((const xmlChar *) "symlink")
#define DTD_ELEM_SYSBOOT ((const xmlChar *) "sysboot")
#define DTD_ELEM_UNINSTALL ((const xmlChar *) "uninstall")
@@ -502,6 +504,15 @@ brand_get_halt(brand_handle_t bh, const char *zonename,
}
int
+brand_get_shutdown(brand_handle_t bh, const char *zonename,
+ const char *zonepath, char *buf, size_t len)
+{
+ struct brand_handle *bhp = (struct brand_handle *)bh;
+ return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
+ buf, len, DTD_ELEM_SHUTDOWN, B_TRUE, B_TRUE));
+}
+
+int
brand_get_initname(brand_handle_t bh, char *buf, size_t len)
{
struct brand_handle *bhp = (struct brand_handle *)bh;
diff --git a/usr/src/lib/libbrand/common/libbrand.h b/usr/src/lib/libbrand/common/libbrand.h
index 19231604a5..6e8a596b3a 100644
--- a/usr/src/lib/libbrand/common/libbrand.h
+++ b/usr/src/lib/libbrand/common/libbrand.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _LIBBRAND_H
@@ -54,6 +55,8 @@ extern int brand_get_clone(brand_handle_t, const char *, const char *,
char *, size_t);
extern int brand_get_detach(brand_handle_t, const char *, const char *,
char *, size_t);
+extern int brand_get_shutdown(brand_handle_t, const char *, const char *,
+ char *, size_t);
extern int brand_get_halt(brand_handle_t, const char *, const char *,
char *, size_t);
extern int brand_get_initname(brand_handle_t, char *, size_t);
diff --git a/usr/src/lib/libbrand/common/mapfile-vers b/usr/src/lib/libbrand/common/mapfile-vers
index 7b961c3c18..7b932b927f 100644
--- a/usr/src/lib/libbrand/common/mapfile-vers
+++ b/usr/src/lib/libbrand/common/mapfile-vers
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
#
#
@@ -66,6 +67,7 @@ SYMBOL_VERSION SUNWprivate {
brand_get_preuninstall;
brand_get_query;
brand_get_sysboot;
+ brand_get_shutdown;
brand_get_uninstall;
brand_get_user_cmd;
brand_get_validatesnap;
diff --git a/usr/src/lib/libbrand/dtd/brand.dtd.1 b/usr/src/lib/libbrand/dtd/brand.dtd.1
index 15542102db..86c0085d51 100644
--- a/usr/src/lib/libbrand/dtd/brand.dtd.1
+++ b/usr/src/lib/libbrand/dtd/brand.dtd.1
@@ -23,6 +23,8 @@
Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
DO NOT EDIT THIS FILE.
+
+ Copyright 2014 Nexenta Systems, Inc. All rights reserved.
-->
<!--
@@ -166,6 +168,27 @@
<!ATTLIST halt>
<!--
+ shutdown
+
+ This is a program which gets run by zoneadmd when a zone is being
+ shutdown gracefully. Currently only asynchronous mode is supported.
+
+ If this program succeeds it should not generate any output. If this
+ program returns an error, any output generated by the program will be
+ sent to the zoneadmd message log.
+
+ The following replacements are performed:
+
+ %z Name of zone
+ %R Zonepath of zone
+ Additional arguments, if any, are appended.
+
+ It has no attributes.
+-->
+<!ELEMENT shutdown (#PCDATA) >
+<!ATTLIST shutdown>
+
+<!--
modname
Path to the kernel module that implements the kernel-level
@@ -607,9 +630,9 @@
<!ELEMENT brand (modname?, initname, login_cmd, forcedlogin_cmd,
user_cmd, install,
- installopts?, boot?, sysboot?, halt?, verify_cfg?,
- verify_adm?, postattach?, postclone?, postinstall?,
- predetach?, attach?, detach?, clone?,
+ installopts?, boot?, sysboot?, halt?, shutdown?,
+ verify_cfg?, verify_adm?, postattach?, postclone?,
+ postinstall?, predetach?, attach?, detach?, clone?,
presnap?, postsnap?, validatesnap?,
preuninstall?, uninstall?,
prestatechange?, poststatechange?, query?,
diff --git a/usr/src/man/man1m/zoneadm.1m b/usr/src/man/man1m/zoneadm.1m
index 13612b3ed1..21a87e2924 100644
--- a/usr/src/man/man1m/zoneadm.1m
+++ b/usr/src/man/man1m/zoneadm.1m
@@ -1,9 +1,10 @@
'\" te
+.\" Copyright 2014 Nexenta Systems, Inc. All rights reserved.
.\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH ZONEADM 1M "Feb 13, 2009"
+.TH ZONEADM 1M "Oct 30, 2013"
.SH NAME
zoneadm \- administer zones
.SH SYNOPSIS
@@ -257,17 +258,6 @@ The source zone must be halted before this subcommand can be used.
.RS 4n
Halt the specified zones. \fBhalt\fR bypasses running the shutdown scripts
inside the zone. It also removes run time resources of the zone.
-.sp
-Use:
-.sp
-.in +2
-.nf
-zlogin \fIzone\fR shutdown
-.fi
-.in -2
-.sp
-
-to cleanly shutdown the zone by running the shutdown scripts.
.RE
.sp
@@ -428,12 +418,26 @@ in the zone.
.sp
.ne 2
.na
-\fB\fBreboot\fR\fR
+\fB\fBreboot\fR\ [\fB--\fR \fIboot_options\fR]]\fR
.ad
.sp .6
.RS 4n
Restart the zones. This is equivalent to a \fBhalt\fR \fBboot\fR sequence. This
-subcommand fails if the specified zones are not active.
+subcommand fails if the specified zones are not active. See \fIboot\fR subcommand
+for the boot options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBshutdown\fR [\fB-r\fR [\fB--\fR \fIboot_options\fR]]\fR
+.ad
+.sp .6
+.RS 4n
+Gracefully shutdown the specified zone. This subcommand waits for all zone
+processes to finish; the default timeout is SCF_PROPERTY_TIMEOUT value from
+the SMF service system/zones. If the \fB-r\fR option is specified, reboot the
+zone. See \fIboot\fR subcommand for the boot options.
.RE
.sp
diff --git a/usr/src/uts/common/sys/zone.h b/usr/src/uts/common/sys/zone.h
index 75d03ee712..cc2a9f0e24 100644
--- a/usr/src/uts/common/sys/zone.h
+++ b/usr/src/uts/common/sys/zone.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SYS_ZONE_H
@@ -231,7 +232,7 @@ typedef enum {
*/
typedef enum zone_cmd {
Z_READY, Z_BOOT, Z_FORCEBOOT, Z_REBOOT, Z_HALT, Z_NOTE_UNINSTALLING,
- Z_MOUNT, Z_FORCEMOUNT, Z_UNMOUNT
+ Z_MOUNT, Z_FORCEMOUNT, Z_UNMOUNT, Z_SHUTDOWN
} zone_cmd_t;
/*