Print this page
2594 implement graceful shutdown for local zones in zoneadm


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.

  24  */
  25 
  26 /*
  27  * zoneadm is a command interpreter for zone administration.  It is all in
  28  * C (i.e., no lex/yacc), and all the argument passing is argc/argv based.
  29  * main() calls parse_and_run() which calls cmd_match(), then invokes the
  30  * appropriate command's handler function.  The rest of the program is the
  31  * handler functions and their helper functions.
  32  *
  33  * Some of the helper functions are used largely to simplify I18N: reducing
  34  * the need for translation notes.  This is particularly true of many of
  35  * the zerror() calls: doing e.g. zerror(gettext("%s failed"), "foo") rather
  36  * than zerror(gettext("foo failed")) with a translation note indicating
  37  * that "foo" need not be translated.
  38  */
  39 
  40 #include <stdio.h>
  41 #include <errno.h>
  42 #include <unistd.h>
  43 #include <signal.h>


 113         char    *name;
 114         int     af;
 115 };
 116 
 117 /* 0755 is the default directory mode. */
 118 #define DEFAULT_DIR_MODE \
 119         (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
 120 
 121 struct cmd {
 122         uint_t  cmd_num;                                /* command number */
 123         char    *cmd_name;                              /* command name */
 124         char    *short_usage;                           /* short form help */
 125         int     (*handler)(int argc, char *argv[]);     /* function to call */
 126 
 127 };
 128 
 129 #define SHELP_HELP      "help"
 130 #define SHELP_BOOT      "boot [-- boot_arguments]"
 131 #define SHELP_HALT      "halt"
 132 #define SHELP_READY     "ready"

 133 #define SHELP_REBOOT    "reboot [-- boot_arguments]"
 134 #define SHELP_LIST      "list [-cipv]"
 135 #define SHELP_VERIFY    "verify"
 136 #define SHELP_INSTALL   "install [brand-specific args]"
 137 #define SHELP_UNINSTALL "uninstall [-F] [brand-specific args]"
 138 #define SHELP_CLONE     "clone [-m method] [-s <ZFS snapshot>] "\
 139         "[brand-specific args] zonename"
 140 #define SHELP_MOVE      "move zonepath"
 141 #define SHELP_DETACH    "detach [-n] [brand-specific args]"
 142 #define SHELP_ATTACH    "attach [-F] [-n <path>] [brand-specific args]"
 143 #define SHELP_MARK      "mark incomplete"
 144 
 145 #define EXEC_PREFIX     "exec "
 146 #define EXEC_LEN        (strlen(EXEC_PREFIX))
 147 #define RMCOMMAND       "/usr/bin/rm -rf"
 148 
 149 static int cleanup_zonepath(char *, boolean_t);
 150 
 151 
 152 static int help_func(int argc, char *argv[]);
 153 static int ready_func(int argc, char *argv[]);
 154 static int boot_func(int argc, char *argv[]);

 155 static int halt_func(int argc, char *argv[]);
 156 static int reboot_func(int argc, char *argv[]);
 157 static int list_func(int argc, char *argv[]);
 158 static int verify_func(int argc, char *argv[]);
 159 static int install_func(int argc, char *argv[]);
 160 static int uninstall_func(int argc, char *argv[]);
 161 static int mount_func(int argc, char *argv[]);
 162 static int unmount_func(int argc, char *argv[]);
 163 static int clone_func(int argc, char *argv[]);
 164 static int move_func(int argc, char *argv[]);
 165 static int detach_func(int argc, char *argv[]);
 166 static int attach_func(int argc, char *argv[]);
 167 static int mark_func(int argc, char *argv[]);
 168 static int apply_func(int argc, char *argv[]);
 169 static int sysboot_func(int argc, char *argv[]);
 170 static int sanity_check(char *zone, int cmd_num, boolean_t running,
 171     boolean_t unsafe_when_running, boolean_t force);
 172 static int cmd_match(char *cmd);
 173 static int verify_details(int, char *argv[]);
 174 static int verify_brand(zone_dochandle_t, int, char *argv[]);
 175 static int invoke_brand_handler(int, char *argv[]);
 176 
 177 static struct cmd cmdtab[] = {
 178         { CMD_HELP,             "help",         SHELP_HELP,     help_func },
 179         { CMD_BOOT,             "boot",         SHELP_BOOT,     boot_func },
 180         { CMD_HALT,             "halt",         SHELP_HALT,     halt_func },
 181         { CMD_READY,            "ready",        SHELP_READY,    ready_func },

 182         { CMD_REBOOT,           "reboot",       SHELP_REBOOT,   reboot_func },
 183         { CMD_LIST,             "list",         SHELP_LIST,     list_func },
 184         { CMD_VERIFY,           "verify",       SHELP_VERIFY,   verify_func },
 185         { CMD_INSTALL,          "install",      SHELP_INSTALL,  install_func },
 186         { CMD_UNINSTALL,        "uninstall",    SHELP_UNINSTALL,
 187             uninstall_func },
 188         /* mount and unmount are private commands for admin/install */
 189         { CMD_MOUNT,            "mount",        NULL,           mount_func },
 190         { CMD_UNMOUNT,          "unmount",      NULL,           unmount_func },
 191         { CMD_CLONE,            "clone",        SHELP_CLONE,    clone_func },
 192         { CMD_MOVE,             "move",         SHELP_MOVE,     move_func },
 193         { CMD_DETACH,           "detach",       SHELP_DETACH,   detach_func },
 194         { CMD_ATTACH,           "attach",       SHELP_ATTACH,   attach_func },
 195         { CMD_MARK,             "mark",         SHELP_MARK,     mark_func },
 196         { CMD_APPLY,            "apply",        NULL,           apply_func },
 197         { CMD_SYSBOOT,          "sysboot",      NULL,           sysboot_func }
 198 };
 199 
 200 /* global variables */
 201 


 215         return (cmdtab[cmd_num].cmd_name);
 216 }
 217 
 218 /* This is a separate function because of gettext() wrapping. */
 219 static char *
 220 long_help(int cmd_num)
 221 {
 222         assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
 223         switch (cmd_num) {
 224         case CMD_HELP:
 225                 return (gettext("Print usage message."));
 226         case CMD_BOOT:
 227                 return (gettext("Activates (boots) specified zone.  See "
 228                     "zoneadm(1m) for valid boot\n\targuments."));
 229         case CMD_HALT:
 230                 return (gettext("Halts specified zone, bypassing shutdown "
 231                     "scripts and removing runtime\n\tresources of the zone."));
 232         case CMD_READY:
 233                 return (gettext("Prepares a zone for running applications but "
 234                     "does not start any user\n\tprocesses in the zone."));




 235         case CMD_REBOOT:
 236                 return (gettext("Restarts the zone (equivalent to a halt / "
 237                     "boot sequence).\n\tFails if the zone is not active.  "
 238                     "See zoneadm(1m) for valid boot\n\targuments."));
 239         case CMD_LIST:
 240                 return (gettext("Lists the current zones, or a "
 241                     "specific zone if indicated.  By default,\n\tall "
 242                     "running zones are listed, though this can be "
 243                     "expanded to all\n\tinstalled zones with the -i "
 244                     "option or all configured zones with the\n\t-c "
 245                     "option.  When used with the general -z <zone> and/or -u "
 246                     "<uuid-match>\n\toptions, lists only the specified "
 247                     "matching zone, but lists it\n\tregardless of its state, "
 248                     "and the -i and -c options are disallowed.  The\n\t-v "
 249                     "option can be used to display verbose information: zone "
 250                     "name, id,\n\tcurrent state, root directory and options.  "
 251                     "The -p option can be used\n\tto request machine-parsable "
 252                     "output.  The -v and -p options are mutually\n\texclusive."
 253                     "  If neither -v nor -p is used, just the zone name is "
 254                     "listed."));


1517          * user will likely need to do some manual cleanup.
1518          */
1519         return (ZONE_SUBPROC_FATAL);
1520 }
1521 
1522 static int
1523 auth_check(char *user, char *zone, int cmd_num)
1524 {
1525         char authname[MAXAUTHS];
1526 
1527         switch (cmd_num) {
1528         case CMD_LIST:
1529         case CMD_HELP:
1530                 return (Z_OK);
1531         case SOURCE_ZONE:
1532                 (void) strlcpy(authname, ZONE_CLONEFROM_AUTH, MAXAUTHS);
1533                 break;
1534         case CMD_BOOT:
1535         case CMD_HALT:
1536         case CMD_READY:

1537         case CMD_REBOOT:
1538         case CMD_SYSBOOT:
1539         case CMD_VERIFY:
1540         case CMD_INSTALL:
1541         case CMD_UNINSTALL:
1542         case CMD_MOUNT:
1543         case CMD_UNMOUNT:
1544         case CMD_CLONE:
1545         case CMD_MOVE:
1546         case CMD_DETACH:
1547         case CMD_ATTACH:
1548         case CMD_MARK:
1549         case CMD_APPLY:
1550         default:
1551                 (void) strlcpy(authname, ZONE_MANAGE_AUTH, MAXAUTHS);
1552                 break;
1553         }
1554         (void) strlcat(authname, KV_OBJECT, MAXAUTHS);
1555         (void) strlcat(authname, zone, MAXAUTHS);
1556         if (chkauthattr(authname, user) == 0) {


1579  *     zone, the name service knows about it.
1580  * 4b. For some operations which expect a zone not to be running, that it is
1581  *     not already running (or ready).
1582  */
1583 static int
1584 sanity_check(char *zone, int cmd_num, boolean_t running,
1585     boolean_t unsafe_when_running, boolean_t force)
1586 {
1587         zone_entry_t *zent;
1588         priv_set_t *privset;
1589         zone_state_t state, min_state;
1590         char kernzone[ZONENAME_MAX];
1591         FILE *fp;
1592 
1593         if (getzoneid() != GLOBAL_ZONEID) {
1594                 switch (cmd_num) {
1595                 case CMD_HALT:
1596                         zerror(gettext("use %s to %s this zone."), "halt(1M)",
1597                             cmd_to_str(cmd_num));
1598                         break;




1599                 case CMD_REBOOT:
1600                         zerror(gettext("use %s to %s this zone."),
1601                             "reboot(1M)", cmd_to_str(cmd_num));
1602                         break;
1603                 default:
1604                         zerror(gettext("must be in the global zone to %s a "
1605                             "zone."), cmd_to_str(cmd_num));
1606                         break;
1607                 }
1608                 return (Z_ERR);
1609         }
1610 
1611         if ((privset = priv_allocset()) == NULL) {
1612                 zerror(gettext("%s failed"), "priv_allocset");
1613                 return (Z_ERR);
1614         }
1615 
1616         if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1617                 zerror(gettext("%s failed"), "getppriv");
1618                 priv_freeset(privset);


1808         /*
1809          * zoneadmd should be the one to decide whether or not to proceed,
1810          * so even though it seems that the fourth parameter below should
1811          * perhaps be B_TRUE, it really shouldn't be.
1812          */
1813         if (sanity_check(target_zone, CMD_HALT, B_FALSE, B_FALSE, B_FALSE)
1814             != Z_OK)
1815                 return (Z_ERR);
1816 
1817         /*
1818          * Invoke brand-specific handler.
1819          */
1820         if (invoke_brand_handler(CMD_HALT, argv) != Z_OK)
1821                 return (Z_ERR);
1822 
1823         zarg.cmd = Z_HALT;
1824         return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale,
1825             B_TRUE) == 0) ?  Z_OK : Z_ERR);
1826 }
1827 





































































1828 static int
1829 reboot_func(int argc, char *argv[])
1830 {
1831         zone_cmd_arg_t zarg;
1832         int arg;
1833 
1834         if (zonecfg_in_alt_root()) {
1835                 zerror(gettext("cannot reboot zone in alternate root"));
1836                 return (Z_ERR);
1837         }
1838 
1839         optind = 0;
1840         if ((arg = getopt(argc, argv, "?")) != EOF) {
1841                 switch (arg) {
1842                 case '?':
1843                         sub_usage(SHELP_REBOOT, CMD_REBOOT);
1844                         return (optopt == '?' ? Z_OK : Z_USAGE);
1845                 default:
1846                         sub_usage(SHELP_REBOOT, CMD_REBOOT);
1847                         return (Z_USAGE);




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  25  */
  26 
  27 /*
  28  * zoneadm is a command interpreter for zone administration.  It is all in
  29  * C (i.e., no lex/yacc), and all the argument passing is argc/argv based.
  30  * main() calls parse_and_run() which calls cmd_match(), then invokes the
  31  * appropriate command's handler function.  The rest of the program is the
  32  * handler functions and their helper functions.
  33  *
  34  * Some of the helper functions are used largely to simplify I18N: reducing
  35  * the need for translation notes.  This is particularly true of many of
  36  * the zerror() calls: doing e.g. zerror(gettext("%s failed"), "foo") rather
  37  * than zerror(gettext("foo failed")) with a translation note indicating
  38  * that "foo" need not be translated.
  39  */
  40 
  41 #include <stdio.h>
  42 #include <errno.h>
  43 #include <unistd.h>
  44 #include <signal.h>


 114         char    *name;
 115         int     af;
 116 };
 117 
 118 /* 0755 is the default directory mode. */
 119 #define DEFAULT_DIR_MODE \
 120         (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
 121 
 122 struct cmd {
 123         uint_t  cmd_num;                                /* command number */
 124         char    *cmd_name;                              /* command name */
 125         char    *short_usage;                           /* short form help */
 126         int     (*handler)(int argc, char *argv[]);     /* function to call */
 127 
 128 };
 129 
 130 #define SHELP_HELP      "help"
 131 #define SHELP_BOOT      "boot [-- boot_arguments]"
 132 #define SHELP_HALT      "halt"
 133 #define SHELP_READY     "ready"
 134 #define SHELP_SHUTDOWN  "shutdown [-r [-- boot_arguments]]"
 135 #define SHELP_REBOOT    "reboot [-- boot_arguments]"
 136 #define SHELP_LIST      "list [-cipv]"
 137 #define SHELP_VERIFY    "verify"
 138 #define SHELP_INSTALL   "install [brand-specific args]"
 139 #define SHELP_UNINSTALL "uninstall [-F] [brand-specific args]"
 140 #define SHELP_CLONE     "clone [-m method] [-s <ZFS snapshot>] "\
 141         "[brand-specific args] zonename"
 142 #define SHELP_MOVE      "move zonepath"
 143 #define SHELP_DETACH    "detach [-n] [brand-specific args]"
 144 #define SHELP_ATTACH    "attach [-F] [-n <path>] [brand-specific args]"
 145 #define SHELP_MARK      "mark incomplete"
 146 
 147 #define EXEC_PREFIX     "exec "
 148 #define EXEC_LEN        (strlen(EXEC_PREFIX))
 149 #define RMCOMMAND       "/usr/bin/rm -rf"
 150 
 151 static int cleanup_zonepath(char *, boolean_t);
 152 
 153 
 154 static int help_func(int argc, char *argv[]);
 155 static int ready_func(int argc, char *argv[]);
 156 static int boot_func(int argc, char *argv[]);
 157 static int shutdown_func(int argc, char *argv[]);
 158 static int halt_func(int argc, char *argv[]);
 159 static int reboot_func(int argc, char *argv[]);
 160 static int list_func(int argc, char *argv[]);
 161 static int verify_func(int argc, char *argv[]);
 162 static int install_func(int argc, char *argv[]);
 163 static int uninstall_func(int argc, char *argv[]);
 164 static int mount_func(int argc, char *argv[]);
 165 static int unmount_func(int argc, char *argv[]);
 166 static int clone_func(int argc, char *argv[]);
 167 static int move_func(int argc, char *argv[]);
 168 static int detach_func(int argc, char *argv[]);
 169 static int attach_func(int argc, char *argv[]);
 170 static int mark_func(int argc, char *argv[]);
 171 static int apply_func(int argc, char *argv[]);
 172 static int sysboot_func(int argc, char *argv[]);
 173 static int sanity_check(char *zone, int cmd_num, boolean_t running,
 174     boolean_t unsafe_when_running, boolean_t force);
 175 static int cmd_match(char *cmd);
 176 static int verify_details(int, char *argv[]);
 177 static int verify_brand(zone_dochandle_t, int, char *argv[]);
 178 static int invoke_brand_handler(int, char *argv[]);
 179 
 180 static struct cmd cmdtab[] = {
 181         { CMD_HELP,             "help",         SHELP_HELP,     help_func },
 182         { CMD_BOOT,             "boot",         SHELP_BOOT,     boot_func },
 183         { CMD_HALT,             "halt",         SHELP_HALT,     halt_func },
 184         { CMD_READY,            "ready",        SHELP_READY,    ready_func },
 185         { CMD_SHUTDOWN,         "shutdown",     SHELP_SHUTDOWN, shutdown_func },
 186         { CMD_REBOOT,           "reboot",       SHELP_REBOOT,   reboot_func },
 187         { CMD_LIST,             "list",         SHELP_LIST,     list_func },
 188         { CMD_VERIFY,           "verify",       SHELP_VERIFY,   verify_func },
 189         { CMD_INSTALL,          "install",      SHELP_INSTALL,  install_func },
 190         { CMD_UNINSTALL,        "uninstall",    SHELP_UNINSTALL,
 191             uninstall_func },
 192         /* mount and unmount are private commands for admin/install */
 193         { CMD_MOUNT,            "mount",        NULL,           mount_func },
 194         { CMD_UNMOUNT,          "unmount",      NULL,           unmount_func },
 195         { CMD_CLONE,            "clone",        SHELP_CLONE,    clone_func },
 196         { CMD_MOVE,             "move",         SHELP_MOVE,     move_func },
 197         { CMD_DETACH,           "detach",       SHELP_DETACH,   detach_func },
 198         { CMD_ATTACH,           "attach",       SHELP_ATTACH,   attach_func },
 199         { CMD_MARK,             "mark",         SHELP_MARK,     mark_func },
 200         { CMD_APPLY,            "apply",        NULL,           apply_func },
 201         { CMD_SYSBOOT,          "sysboot",      NULL,           sysboot_func }
 202 };
 203 
 204 /* global variables */
 205 


 219         return (cmdtab[cmd_num].cmd_name);
 220 }
 221 
 222 /* This is a separate function because of gettext() wrapping. */
 223 static char *
 224 long_help(int cmd_num)
 225 {
 226         assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
 227         switch (cmd_num) {
 228         case CMD_HELP:
 229                 return (gettext("Print usage message."));
 230         case CMD_BOOT:
 231                 return (gettext("Activates (boots) specified zone.  See "
 232                     "zoneadm(1m) for valid boot\n\targuments."));
 233         case CMD_HALT:
 234                 return (gettext("Halts specified zone, bypassing shutdown "
 235                     "scripts and removing runtime\n\tresources of the zone."));
 236         case CMD_READY:
 237                 return (gettext("Prepares a zone for running applications but "
 238                     "does not start any user\n\tprocesses in the zone."));
 239         case CMD_SHUTDOWN:
 240                 return (gettext("Gracefully shutdown the zone or reboot if "
 241                     "the '-r' option is specified.\n\t"
 242                     "See zoneadm(1m) for valid boot arguments."));
 243         case CMD_REBOOT:
 244                 return (gettext("Restarts the zone (equivalent to a halt / "
 245                     "boot sequence).\n\tFails if the zone is not active.  "
 246                     "See zoneadm(1m) for valid boot\n\targuments."));
 247         case CMD_LIST:
 248                 return (gettext("Lists the current zones, or a "
 249                     "specific zone if indicated.  By default,\n\tall "
 250                     "running zones are listed, though this can be "
 251                     "expanded to all\n\tinstalled zones with the -i "
 252                     "option or all configured zones with the\n\t-c "
 253                     "option.  When used with the general -z <zone> and/or -u "
 254                     "<uuid-match>\n\toptions, lists only the specified "
 255                     "matching zone, but lists it\n\tregardless of its state, "
 256                     "and the -i and -c options are disallowed.  The\n\t-v "
 257                     "option can be used to display verbose information: zone "
 258                     "name, id,\n\tcurrent state, root directory and options.  "
 259                     "The -p option can be used\n\tto request machine-parsable "
 260                     "output.  The -v and -p options are mutually\n\texclusive."
 261                     "  If neither -v nor -p is used, just the zone name is "
 262                     "listed."));


1525          * user will likely need to do some manual cleanup.
1526          */
1527         return (ZONE_SUBPROC_FATAL);
1528 }
1529 
1530 static int
1531 auth_check(char *user, char *zone, int cmd_num)
1532 {
1533         char authname[MAXAUTHS];
1534 
1535         switch (cmd_num) {
1536         case CMD_LIST:
1537         case CMD_HELP:
1538                 return (Z_OK);
1539         case SOURCE_ZONE:
1540                 (void) strlcpy(authname, ZONE_CLONEFROM_AUTH, MAXAUTHS);
1541                 break;
1542         case CMD_BOOT:
1543         case CMD_HALT:
1544         case CMD_READY:
1545         case CMD_SHUTDOWN:
1546         case CMD_REBOOT:
1547         case CMD_SYSBOOT:
1548         case CMD_VERIFY:
1549         case CMD_INSTALL:
1550         case CMD_UNINSTALL:
1551         case CMD_MOUNT:
1552         case CMD_UNMOUNT:
1553         case CMD_CLONE:
1554         case CMD_MOVE:
1555         case CMD_DETACH:
1556         case CMD_ATTACH:
1557         case CMD_MARK:
1558         case CMD_APPLY:
1559         default:
1560                 (void) strlcpy(authname, ZONE_MANAGE_AUTH, MAXAUTHS);
1561                 break;
1562         }
1563         (void) strlcat(authname, KV_OBJECT, MAXAUTHS);
1564         (void) strlcat(authname, zone, MAXAUTHS);
1565         if (chkauthattr(authname, user) == 0) {


1588  *     zone, the name service knows about it.
1589  * 4b. For some operations which expect a zone not to be running, that it is
1590  *     not already running (or ready).
1591  */
1592 static int
1593 sanity_check(char *zone, int cmd_num, boolean_t running,
1594     boolean_t unsafe_when_running, boolean_t force)
1595 {
1596         zone_entry_t *zent;
1597         priv_set_t *privset;
1598         zone_state_t state, min_state;
1599         char kernzone[ZONENAME_MAX];
1600         FILE *fp;
1601 
1602         if (getzoneid() != GLOBAL_ZONEID) {
1603                 switch (cmd_num) {
1604                 case CMD_HALT:
1605                         zerror(gettext("use %s to %s this zone."), "halt(1M)",
1606                             cmd_to_str(cmd_num));
1607                         break;
1608                 case CMD_SHUTDOWN:
1609                         zerror(gettext("use %s to %s this zone."),
1610                             "shutdown(1M)", cmd_to_str(cmd_num));
1611                         break;
1612                 case CMD_REBOOT:
1613                         zerror(gettext("use %s to %s this zone."),
1614                             "reboot(1M)", cmd_to_str(cmd_num));
1615                         break;
1616                 default:
1617                         zerror(gettext("must be in the global zone to %s a "
1618                             "zone."), cmd_to_str(cmd_num));
1619                         break;
1620                 }
1621                 return (Z_ERR);
1622         }
1623 
1624         if ((privset = priv_allocset()) == NULL) {
1625                 zerror(gettext("%s failed"), "priv_allocset");
1626                 return (Z_ERR);
1627         }
1628 
1629         if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1630                 zerror(gettext("%s failed"), "getppriv");
1631                 priv_freeset(privset);


1821         /*
1822          * zoneadmd should be the one to decide whether or not to proceed,
1823          * so even though it seems that the fourth parameter below should
1824          * perhaps be B_TRUE, it really shouldn't be.
1825          */
1826         if (sanity_check(target_zone, CMD_HALT, B_FALSE, B_FALSE, B_FALSE)
1827             != Z_OK)
1828                 return (Z_ERR);
1829 
1830         /*
1831          * Invoke brand-specific handler.
1832          */
1833         if (invoke_brand_handler(CMD_HALT, argv) != Z_OK)
1834                 return (Z_ERR);
1835 
1836         zarg.cmd = Z_HALT;
1837         return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale,
1838             B_TRUE) == 0) ?  Z_OK : Z_ERR);
1839 }
1840 
1841 static int
1842 shutdown_func(int argc, char *argv[])
1843 {
1844         zone_cmd_arg_t zarg;
1845         int arg;
1846         boolean_t reboot = B_FALSE;
1847 
1848         zarg.cmd = Z_SHUTDOWN;
1849 
1850         if (zonecfg_in_alt_root()) {
1851                 zerror(gettext("cannot shut down zone in alternate root"));
1852                 return (Z_ERR);
1853         }
1854 
1855         optind = 0;
1856         while ((arg = getopt(argc, argv, "?r")) != EOF) {
1857                 switch (arg) {
1858                 case '?':
1859                         sub_usage(SHELP_SHUTDOWN, CMD_SHUTDOWN);
1860                         return (optopt == '?' ? Z_OK : Z_USAGE);
1861                 case 'r':
1862                         reboot = B_TRUE;
1863                         break;
1864                 default:
1865                         sub_usage(SHELP_SHUTDOWN, CMD_SHUTDOWN);
1866                         return (Z_USAGE);
1867                 }
1868         }
1869 
1870         zarg.bootbuf[0] = '\0';
1871         for (; optind < argc; optind++) {
1872                 if (strlcat(zarg.bootbuf, argv[optind],
1873                     sizeof (zarg.bootbuf)) >= sizeof (zarg.bootbuf)) {
1874                         zerror(gettext("Boot argument list too long"));
1875                         return (Z_ERR);
1876                 }
1877                 if (optind < argc - 1)
1878                         if (strlcat(zarg.bootbuf, " ", sizeof (zarg.bootbuf)) >=
1879                             sizeof (zarg.bootbuf)) {
1880                                 zerror(gettext("Boot argument list too long"));
1881                                 return (Z_ERR);
1882                         }
1883         }
1884 
1885         /*
1886          * zoneadmd should be the one to decide whether or not to proceed,
1887          * so even though it seems that the third parameter below should
1888          * perhaps be B_TRUE, it really shouldn't be.
1889          */
1890         if (sanity_check(target_zone, CMD_SHUTDOWN, B_TRUE, B_FALSE, B_FALSE)
1891             != Z_OK)
1892                 return (Z_ERR);
1893 
1894         if (zonecfg_call_zoneadmd(target_zone, &zarg, locale, B_TRUE) != Z_OK)
1895                 return (Z_ERR);
1896 
1897         if (reboot) {
1898                 if (sanity_check(target_zone, CMD_BOOT, B_FALSE, B_FALSE,
1899                     B_FALSE) != Z_OK)
1900                         return (Z_ERR);
1901 
1902                 zarg.cmd = Z_BOOT;
1903                 if (zonecfg_call_zoneadmd(target_zone, &zarg, locale,
1904                     B_TRUE) != Z_OK)
1905                         return (Z_ERR);
1906         }
1907         return (Z_OK);
1908 }
1909 
1910 static int
1911 reboot_func(int argc, char *argv[])
1912 {
1913         zone_cmd_arg_t zarg;
1914         int arg;
1915 
1916         if (zonecfg_in_alt_root()) {
1917                 zerror(gettext("cannot reboot zone in alternate root"));
1918                 return (Z_ERR);
1919         }
1920 
1921         optind = 0;
1922         if ((arg = getopt(argc, argv, "?")) != EOF) {
1923                 switch (arg) {
1924                 case '?':
1925                         sub_usage(SHELP_REBOOT, CMD_REBOOT);
1926                         return (optopt == '?' ? Z_OK : Z_USAGE);
1927                 default:
1928                         sub_usage(SHELP_REBOOT, CMD_REBOOT);
1929                         return (Z_USAGE);