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

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/zoneadm/zoneadm.c
          +++ new/usr/src/cmd/zoneadm/zoneadm.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * zoneadm is a command interpreter for zone administration.  It is all in
  28   29   * C (i.e., no lex/yacc), and all the argument passing is argc/argv based.
  29   30   * main() calls parse_and_run() which calls cmd_match(), then invokes the
  30   31   * appropriate command's handler function.  The rest of the program is the
  31   32   * handler functions and their helper functions.
  32   33   *
  33   34   * Some of the helper functions are used largely to simplify I18N: reducing
↓ open down ↓ 89 lines elided ↑ open up ↑
 123  124          char    *cmd_name;                              /* command name */
 124  125          char    *short_usage;                           /* short form help */
 125  126          int     (*handler)(int argc, char *argv[]);     /* function to call */
 126  127  
 127  128  };
 128  129  
 129  130  #define SHELP_HELP      "help"
 130  131  #define SHELP_BOOT      "boot [-- boot_arguments]"
 131  132  #define SHELP_HALT      "halt"
 132  133  #define SHELP_READY     "ready"
      134 +#define SHELP_SHUTDOWN  "shutdown [-r [-- boot_arguments]]"
 133  135  #define SHELP_REBOOT    "reboot [-- boot_arguments]"
 134  136  #define SHELP_LIST      "list [-cipv]"
 135  137  #define SHELP_VERIFY    "verify"
 136  138  #define SHELP_INSTALL   "install [brand-specific args]"
 137  139  #define SHELP_UNINSTALL "uninstall [-F] [brand-specific args]"
 138  140  #define SHELP_CLONE     "clone [-m method] [-s <ZFS snapshot>] "\
 139  141          "[brand-specific args] zonename"
 140  142  #define SHELP_MOVE      "move zonepath"
 141  143  #define SHELP_DETACH    "detach [-n] [brand-specific args]"
 142  144  #define SHELP_ATTACH    "attach [-F] [-n <path>] [brand-specific args]"
↓ open down ↓ 2 lines elided ↑ open up ↑
 145  147  #define EXEC_PREFIX     "exec "
 146  148  #define EXEC_LEN        (strlen(EXEC_PREFIX))
 147  149  #define RMCOMMAND       "/usr/bin/rm -rf"
 148  150  
 149  151  static int cleanup_zonepath(char *, boolean_t);
 150  152  
 151  153  
 152  154  static int help_func(int argc, char *argv[]);
 153  155  static int ready_func(int argc, char *argv[]);
 154  156  static int boot_func(int argc, char *argv[]);
      157 +static int shutdown_func(int argc, char *argv[]);
 155  158  static int halt_func(int argc, char *argv[]);
 156  159  static int reboot_func(int argc, char *argv[]);
 157  160  static int list_func(int argc, char *argv[]);
 158  161  static int verify_func(int argc, char *argv[]);
 159  162  static int install_func(int argc, char *argv[]);
 160  163  static int uninstall_func(int argc, char *argv[]);
 161  164  static int mount_func(int argc, char *argv[]);
 162  165  static int unmount_func(int argc, char *argv[]);
 163  166  static int clone_func(int argc, char *argv[]);
 164  167  static int move_func(int argc, char *argv[]);
↓ open down ↓ 7 lines elided ↑ open up ↑
 172  175  static int cmd_match(char *cmd);
 173  176  static int verify_details(int, char *argv[]);
 174  177  static int verify_brand(zone_dochandle_t, int, char *argv[]);
 175  178  static int invoke_brand_handler(int, char *argv[]);
 176  179  
 177  180  static struct cmd cmdtab[] = {
 178  181          { CMD_HELP,             "help",         SHELP_HELP,     help_func },
 179  182          { CMD_BOOT,             "boot",         SHELP_BOOT,     boot_func },
 180  183          { CMD_HALT,             "halt",         SHELP_HALT,     halt_func },
 181  184          { CMD_READY,            "ready",        SHELP_READY,    ready_func },
      185 +        { CMD_SHUTDOWN,         "shutdown",     SHELP_SHUTDOWN, shutdown_func },
 182  186          { CMD_REBOOT,           "reboot",       SHELP_REBOOT,   reboot_func },
 183  187          { CMD_LIST,             "list",         SHELP_LIST,     list_func },
 184  188          { CMD_VERIFY,           "verify",       SHELP_VERIFY,   verify_func },
 185  189          { CMD_INSTALL,          "install",      SHELP_INSTALL,  install_func },
 186  190          { CMD_UNINSTALL,        "uninstall",    SHELP_UNINSTALL,
 187  191              uninstall_func },
 188  192          /* mount and unmount are private commands for admin/install */
 189  193          { CMD_MOUNT,            "mount",        NULL,           mount_func },
 190  194          { CMD_UNMOUNT,          "unmount",      NULL,           unmount_func },
 191  195          { CMD_CLONE,            "clone",        SHELP_CLONE,    clone_func },
↓ open down ↓ 33 lines elided ↑ open up ↑
 225  229                  return (gettext("Print usage message."));
 226  230          case CMD_BOOT:
 227  231                  return (gettext("Activates (boots) specified zone.  See "
 228  232                      "zoneadm(1m) for valid boot\n\targuments."));
 229  233          case CMD_HALT:
 230  234                  return (gettext("Halts specified zone, bypassing shutdown "
 231  235                      "scripts and removing runtime\n\tresources of the zone."));
 232  236          case CMD_READY:
 233  237                  return (gettext("Prepares a zone for running applications but "
 234  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."));
 235  243          case CMD_REBOOT:
 236  244                  return (gettext("Restarts the zone (equivalent to a halt / "
 237  245                      "boot sequence).\n\tFails if the zone is not active.  "
 238  246                      "See zoneadm(1m) for valid boot\n\targuments."));
 239  247          case CMD_LIST:
 240  248                  return (gettext("Lists the current zones, or a "
 241  249                      "specific zone if indicated.  By default,\n\tall "
 242  250                      "running zones are listed, though this can be "
 243  251                      "expanded to all\n\tinstalled zones with the -i "
 244  252                      "option or all configured zones with the\n\t-c "
↓ open down ↓ 1282 lines elided ↑ open up ↑
1527 1535          switch (cmd_num) {
1528 1536          case CMD_LIST:
1529 1537          case CMD_HELP:
1530 1538                  return (Z_OK);
1531 1539          case SOURCE_ZONE:
1532 1540                  (void) strlcpy(authname, ZONE_CLONEFROM_AUTH, MAXAUTHS);
1533 1541                  break;
1534 1542          case CMD_BOOT:
1535 1543          case CMD_HALT:
1536 1544          case CMD_READY:
     1545 +        case CMD_SHUTDOWN:
1537 1546          case CMD_REBOOT:
1538 1547          case CMD_SYSBOOT:
1539 1548          case CMD_VERIFY:
1540 1549          case CMD_INSTALL:
1541 1550          case CMD_UNINSTALL:
1542 1551          case CMD_MOUNT:
1543 1552          case CMD_UNMOUNT:
1544 1553          case CMD_CLONE:
1545 1554          case CMD_MOVE:
1546 1555          case CMD_DETACH:
↓ open down ↓ 42 lines elided ↑ open up ↑
1589 1598          zone_state_t state, min_state;
1590 1599          char kernzone[ZONENAME_MAX];
1591 1600          FILE *fp;
1592 1601  
1593 1602          if (getzoneid() != GLOBAL_ZONEID) {
1594 1603                  switch (cmd_num) {
1595 1604                  case CMD_HALT:
1596 1605                          zerror(gettext("use %s to %s this zone."), "halt(1M)",
1597 1606                              cmd_to_str(cmd_num));
1598 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;
1599 1612                  case CMD_REBOOT:
1600 1613                          zerror(gettext("use %s to %s this zone."),
1601 1614                              "reboot(1M)", cmd_to_str(cmd_num));
1602 1615                          break;
1603 1616                  default:
1604 1617                          zerror(gettext("must be in the global zone to %s a "
1605 1618                              "zone."), cmd_to_str(cmd_num));
1606 1619                          break;
1607 1620                  }
1608 1621                  return (Z_ERR);
↓ open down ↓ 209 lines elided ↑ open up ↑
1818 1831           * Invoke brand-specific handler.
1819 1832           */
1820 1833          if (invoke_brand_handler(CMD_HALT, argv) != Z_OK)
1821 1834                  return (Z_ERR);
1822 1835  
1823 1836          zarg.cmd = Z_HALT;
1824 1837          return ((zonecfg_call_zoneadmd(target_zone, &zarg, locale,
1825 1838              B_TRUE) == 0) ?  Z_OK : Z_ERR);
1826 1839  }
1827 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 +
1828 1910  static int
1829 1911  reboot_func(int argc, char *argv[])
1830 1912  {
1831 1913          zone_cmd_arg_t zarg;
1832 1914          int arg;
1833 1915  
1834 1916          if (zonecfg_in_alt_root()) {
1835 1917                  zerror(gettext("cannot reboot zone in alternate root"));
1836 1918                  return (Z_ERR);
1837 1919          }
↓ open down ↓ 3852 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX