[systemd-devel] [PATCH 3/8] power: refactor the three power management binaries to src/power

Shawn Landden shawn at churchofgit.com
Fri Feb 20 14:31:00 PST 2015


---
 Makefile.am               |   6 +-
 src/core/shutdown.c       | 420 -----------------------------------------
 src/power/Makefile        |  28 +++
 src/power/shutdown.c      | 420 +++++++++++++++++++++++++++++++++++++++++
 src/power/shutdownd.c     | 461 ++++++++++++++++++++++++++++++++++++++++++++++
 src/power/sleep.c         | 219 ++++++++++++++++++++++
 src/shutdownd/Makefile    |   1 -
 src/shutdownd/shutdownd.c | 461 ----------------------------------------------
 src/sleep/Makefile        |   1 -
 src/sleep/sleep.c         | 219 ----------------------
 10 files changed, 1131 insertions(+), 1105 deletions(-)
 delete mode 100644 src/core/shutdown.c
 create mode 100644 src/power/Makefile
 create mode 100644 src/power/shutdown.c
 create mode 100644 src/power/shutdownd.c
 create mode 100644 src/power/sleep.c
 delete mode 120000 src/shutdownd/Makefile
 delete mode 100644 src/shutdownd/shutdownd.c
 delete mode 120000 src/sleep/Makefile
 delete mode 100644 src/sleep/sleep.c

diff --git a/Makefile.am b/Makefile.am
index ba63f68..52ec7ef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2122,7 +2122,7 @@ systemd_update_done_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_shutdownd_SOURCES = \
-	src/shutdownd/shutdownd.c
+	src/power/shutdownd.c
 
 systemd_shutdownd_LDADD = \
 	libsystemd-label.la \
@@ -2136,7 +2136,7 @@ dist_doc_DATA += \
 systemd_shutdown_SOURCES = \
 	src/core/umount.c \
 	src/core/umount.h \
-	src/core/shutdown.c \
+	src/power/shutdown.c \
 	src/core/mount-setup.c \
 	src/core/mount-setup.h \
 	src/core/killall.h \
@@ -2340,7 +2340,7 @@ systemd_sysctl_LDADD = \
 
 # ------------------------------------------------------------------------------
 systemd_sleep_SOURCES = \
-	src/sleep/sleep.c
+	src/power/sleep.c
 
 systemd_sleep_LDADD = \
 	libsystemd-shared.la
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
deleted file mode 100644
index 71f001a..0000000
--- a/src/core/shutdown.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 ProFUSION embedded systems
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
-#include <sys/syscall.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-
-#include "missing.h"
-#include "log.h"
-#include "fileio.h"
-#include "umount.h"
-#include "util.h"
-#include "mkdir.h"
-#include "virt.h"
-#include "watchdog.h"
-#include "killall.h"
-#include "cgroup-util.h"
-#include "def.h"
-#include "switch-root.h"
-#include "strv.h"
-
-#define FINALIZE_ATTEMPTS 50
-
-static char* arg_verb;
-
-static int parse_argv(int argc, char *argv[]) {
-        enum {
-                ARG_LOG_LEVEL = 0x100,
-                ARG_LOG_TARGET,
-                ARG_LOG_COLOR,
-                ARG_LOG_LOCATION,
-        };
-
-        static const struct option options[] = {
-                { "log-level",     required_argument, NULL, ARG_LOG_LEVEL    },
-                { "log-target",    required_argument, NULL, ARG_LOG_TARGET   },
-                { "log-color",     optional_argument, NULL, ARG_LOG_COLOR    },
-                { "log-location",  optional_argument, NULL, ARG_LOG_LOCATION },
-                {}
-        };
-
-        int c, r;
-
-        assert(argc >= 1);
-        assert(argv);
-
-        /* "-" prevents getopt from permuting argv[] and moving the verb away
-         * from argv[1]. Our interface to initrd promises it'll be there. */
-        while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
-                switch (c) {
-
-                case ARG_LOG_LEVEL:
-                        r = log_set_max_level_from_string(optarg);
-                        if (r < 0)
-                                log_error("Failed to parse log level %s, ignoring.", optarg);
-
-                        break;
-
-                case ARG_LOG_TARGET:
-                        r = log_set_target_from_string(optarg);
-                        if (r < 0)
-                                log_error("Failed to parse log target %s, ignoring", optarg);
-
-                        break;
-
-                case ARG_LOG_COLOR:
-
-                        if (optarg) {
-                                r = log_show_color_from_string(optarg);
-                                if (r < 0)
-                                        log_error("Failed to parse log color setting %s, ignoring", optarg);
-                        } else
-                                log_show_color(true);
-
-                        break;
-
-                case ARG_LOG_LOCATION:
-                        if (optarg) {
-                                r = log_show_location_from_string(optarg);
-                                if (r < 0)
-                                        log_error("Failed to parse log location setting %s, ignoring", optarg);
-                        } else
-                                log_show_location(true);
-
-                        break;
-
-                case '\001':
-                        if (!arg_verb)
-                                arg_verb = optarg;
-                        else
-                                log_error("Excess arguments, ignoring");
-                        break;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        assert_not_reached("Unhandled option code.");
-                }
-
-        if (!arg_verb) {
-                log_error("Verb argument missing.");
-                return -EINVAL;
-        }
-
-        return 0;
-}
-
-static int switch_root_initramfs(void) {
-        if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0)
-                return log_error_errno(errno, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
-
-        if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0)
-                return log_error_errno(errno, "Failed to make /run/initramfs private mount: %m");
-
-        /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
-         * /run/initramfs/shutdown will take care of these.
-         * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
-         */
-        return switch_root("/run/initramfs", "/oldroot", false, MS_BIND);
-}
-
-
-int main(int argc, char *argv[]) {
-        bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
-        bool in_container, use_watchdog = false;
-        _cleanup_free_ char *cgroup = NULL;
-        char *arguments[3];
-        unsigned retries;
-        int cmd, r;
-        static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
-
-        log_parse_environment();
-        r = parse_argv(argc, argv);
-        if (r < 0)
-                goto error;
-
-        /* journald will die if not gone yet. The log target defaults
-         * to console, but may have been changed by command line options. */
-
-        log_close_console(); /* force reopen of /dev/console */
-        log_open();
-
-        umask(0022);
-
-        if (getpid() != 1) {
-                log_error("Not executed by init (PID 1).");
-                r = -EPERM;
-                goto error;
-        }
-
-        if (streq(arg_verb, "reboot"))
-                cmd = RB_AUTOBOOT;
-        else if (streq(arg_verb, "poweroff"))
-                cmd = RB_POWER_OFF;
-        else if (streq(arg_verb, "halt"))
-                cmd = RB_HALT_SYSTEM;
-        else if (streq(arg_verb, "kexec"))
-                cmd = LINUX_REBOOT_CMD_KEXEC;
-        else {
-                r = -EINVAL;
-                log_error("Unknown action '%s'.", arg_verb);
-                goto error;
-        }
-
-        cg_get_root_path(&cgroup);
-
-        use_watchdog = !!getenv("WATCHDOG_USEC");
-
-        /* lock us into memory */
-        mlockall(MCL_CURRENT|MCL_FUTURE);
-
-        log_info("Sending SIGTERM to remaining processes...");
-        broadcast_signal(SIGTERM, true, true);
-
-        log_info("Sending SIGKILL to remaining processes...");
-        broadcast_signal(SIGKILL, true, false);
-
-        in_container = detect_container(NULL) > 0;
-
-        need_umount = !in_container;
-        need_swapoff = !in_container;
-        need_loop_detach = !in_container;
-        need_dm_detach = !in_container;
-
-        /* Unmount all mountpoints, swaps, and loopback devices */
-        for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
-                bool changed = false;
-
-                if (use_watchdog)
-                        watchdog_ping();
-
-                /* Let's trim the cgroup tree on each iteration so
-                   that we leave an empty cgroup tree around, so that
-                   container managers get a nice notify event when we
-                   are down */
-                if (cgroup)
-                        cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
-
-                if (need_umount) {
-                        log_info("Unmounting file systems.");
-                        r = umount_all(&changed);
-                        if (r == 0) {
-                                need_umount = false;
-                                log_info("All filesystems unmounted.");
-                        } else if (r > 0)
-                                log_info("Not all file systems unmounted, %d left.", r);
-                        else
-                                log_error_errno(r, "Failed to unmount file systems: %m");
-                }
-
-                if (need_swapoff) {
-                        log_info("Deactivating swaps.");
-                        r = swapoff_all(&changed);
-                        if (r == 0) {
-                                need_swapoff = false;
-                                log_info("All swaps deactivated.");
-                        } else if (r > 0)
-                                log_info("Not all swaps deactivated, %d left.", r);
-                        else
-                                log_error_errno(r, "Failed to deactivate swaps: %m");
-                }
-
-                if (need_loop_detach) {
-                        log_info("Detaching loop devices.");
-                        r = loopback_detach_all(&changed);
-                        if (r == 0) {
-                                need_loop_detach = false;
-                                log_info("All loop devices detached.");
-                        } else if (r > 0)
-                                log_info("Not all loop devices detached, %d left.", r);
-                        else
-                                log_error_errno(r, "Failed to detach loop devices: %m");
-                }
-
-                if (need_dm_detach) {
-                        log_info("Detaching DM devices.");
-                        r = dm_detach_all(&changed);
-                        if (r == 0) {
-                                need_dm_detach = false;
-                                log_info("All DM devices detached.");
-                        } else if (r > 0)
-                                log_info("Not all DM devices detached, %d left.", r);
-                        else
-                                log_error_errno(r, "Failed to detach DM devices: %m");
-                }
-
-                if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
-                        if (retries > 0)
-                                log_info("All filesystems, swaps, loop devices, DM devices detached.");
-                        /* Yay, done */
-                        goto initrd_jump;
-                }
-
-                /* If in this iteration we didn't manage to
-                 * unmount/deactivate anything, we simply give up */
-                if (!changed) {
-                        log_info("Cannot finalize remaining%s%s%s%s continuing.",
-                                 need_umount ? " file systems," : "",
-                                 need_swapoff ? " swap devices," : "",
-                                 need_loop_detach ? " loop devices," : "",
-                                 need_dm_detach ? " DM devices," : "");
-                        goto initrd_jump;
-                }
-
-                log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
-                          retries + 1,
-                          need_umount ? " file systems," : "",
-                          need_swapoff ? " swap devices," : "",
-                          need_loop_detach ? " loop devices," : "",
-                          need_dm_detach ? " DM devices," : "");
-        }
-
-        log_error("Too many iterations, giving up.");
-
- initrd_jump:
-
-        arguments[0] = NULL;
-        arguments[1] = arg_verb;
-        arguments[2] = NULL;
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
-
-        if (!in_container && !in_initrd() &&
-            access("/run/initramfs/shutdown", X_OK) == 0) {
-                r = switch_root_initramfs();
-                if (r >= 0) {
-                        argv[0] = (char*) "/shutdown";
-
-                        setsid();
-                        make_console_stdio();
-
-                        log_info("Successfully changed into root pivot.\n"
-                                 "Returning to initrd...");
-
-                        execv("/shutdown", argv);
-                        log_error_errno(errno, "Failed to execute shutdown binary: %m");
-                } else
-                        log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m");
-
-        }
-
-        if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
-                log_error("Failed to finalize %s%s%s%s ignoring",
-                          need_umount ? " file systems," : "",
-                          need_swapoff ? " swap devices," : "",
-                          need_loop_detach ? " loop devices," : "",
-                          need_dm_detach ? " DM devices," : "");
-
-        /* The kernel will automaticall flush ATA disks and suchlike
-         * on reboot(), but the file systems need to be synce'd
-         * explicitly in advance. So let's do this here, but not
-         * needlessly slow down containers. */
-        if (!in_container)
-                sync();
-
-        switch (cmd) {
-
-        case LINUX_REBOOT_CMD_KEXEC:
-
-                if (!in_container) {
-                        /* We cheat and exec kexec to avoid doing all its work */
-                        pid_t pid;
-
-                        log_info("Rebooting with kexec.");
-
-                        pid = fork();
-                        if (pid < 0)
-                                log_error_errno(errno, "Failed to fork: %m");
-                        else if (pid == 0) {
-
-                                const char * const args[] = {
-                                        KEXEC, "-e", NULL
-                                };
-
-                                /* Child */
-
-                                execv(args[0], (char * const *) args);
-                                _exit(EXIT_FAILURE);
-                        } else
-                                wait_for_terminate_and_warn("kexec", pid, true);
-                }
-
-                cmd = RB_AUTOBOOT;
-                /* Fall through */
-
-        case RB_AUTOBOOT:
-
-                if (!in_container) {
-                        _cleanup_free_ char *param = NULL;
-
-                        if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
-                                log_info("Rebooting with argument '%s'.", param);
-                                syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
-                        }
-                }
-
-                log_info("Rebooting.");
-                break;
-
-        case RB_POWER_OFF:
-                log_info("Powering off.");
-                break;
-
-        case RB_HALT_SYSTEM:
-                log_info("Halting system.");
-                break;
-
-        default:
-                assert_not_reached("Unknown magic");
-        }
-
-        reboot(cmd);
-        if (errno == EPERM && in_container) {
-                /* If we are in a container, and we lacked
-                 * CAP_SYS_BOOT just exit, this will kill our
-                 * container for good. */
-                log_info("Exiting container.");
-                exit(0);
-        }
-
-        log_error_errno(errno, "Failed to invoke reboot(): %m");
-        r = -errno;
-
-  error:
-        log_emergency_errno(r, "Critical error while doing system shutdown: %m");
-
-        freeze();
-}
diff --git a/src/power/Makefile b/src/power/Makefile
new file mode 100644
index 0000000..9d07505
--- /dev/null
+++ b/src/power/Makefile
@@ -0,0 +1,28 @@
+#  This file is part of systemd.
+#
+#  Copyright 2010 Lennart Poettering
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+#
+#  systemd is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public License
+#  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+# This file is a dirty trick to simplify compilation from within
+# emacs. This file is not intended to be distributed. So, don't touch
+# it, even better ignore it!
+
+all:
+	$(MAKE) -C ..
+
+clean:
+	$(MAKE) -C .. clean
+
+.PHONY: all clean
diff --git a/src/power/shutdown.c b/src/power/shutdown.c
new file mode 100644
index 0000000..71f001a
--- /dev/null
+++ b/src/power/shutdown.c
@@ -0,0 +1,420 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 ProFUSION embedded systems
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/reboot.h>
+#include <linux/reboot.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/syscall.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "missing.h"
+#include "log.h"
+#include "fileio.h"
+#include "umount.h"
+#include "util.h"
+#include "mkdir.h"
+#include "virt.h"
+#include "watchdog.h"
+#include "killall.h"
+#include "cgroup-util.h"
+#include "def.h"
+#include "switch-root.h"
+#include "strv.h"
+
+#define FINALIZE_ATTEMPTS 50
+
+static char* arg_verb;
+
+static int parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_LOG_LEVEL = 0x100,
+                ARG_LOG_TARGET,
+                ARG_LOG_COLOR,
+                ARG_LOG_LOCATION,
+        };
+
+        static const struct option options[] = {
+                { "log-level",     required_argument, NULL, ARG_LOG_LEVEL    },
+                { "log-target",    required_argument, NULL, ARG_LOG_TARGET   },
+                { "log-color",     optional_argument, NULL, ARG_LOG_COLOR    },
+                { "log-location",  optional_argument, NULL, ARG_LOG_LOCATION },
+                {}
+        };
+
+        int c, r;
+
+        assert(argc >= 1);
+        assert(argv);
+
+        /* "-" prevents getopt from permuting argv[] and moving the verb away
+         * from argv[1]. Our interface to initrd promises it'll be there. */
+        while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
+                switch (c) {
+
+                case ARG_LOG_LEVEL:
+                        r = log_set_max_level_from_string(optarg);
+                        if (r < 0)
+                                log_error("Failed to parse log level %s, ignoring.", optarg);
+
+                        break;
+
+                case ARG_LOG_TARGET:
+                        r = log_set_target_from_string(optarg);
+                        if (r < 0)
+                                log_error("Failed to parse log target %s, ignoring", optarg);
+
+                        break;
+
+                case ARG_LOG_COLOR:
+
+                        if (optarg) {
+                                r = log_show_color_from_string(optarg);
+                                if (r < 0)
+                                        log_error("Failed to parse log color setting %s, ignoring", optarg);
+                        } else
+                                log_show_color(true);
+
+                        break;
+
+                case ARG_LOG_LOCATION:
+                        if (optarg) {
+                                r = log_show_location_from_string(optarg);
+                                if (r < 0)
+                                        log_error("Failed to parse log location setting %s, ignoring", optarg);
+                        } else
+                                log_show_location(true);
+
+                        break;
+
+                case '\001':
+                        if (!arg_verb)
+                                arg_verb = optarg;
+                        else
+                                log_error("Excess arguments, ignoring");
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option code.");
+                }
+
+        if (!arg_verb) {
+                log_error("Verb argument missing.");
+                return -EINVAL;
+        }
+
+        return 0;
+}
+
+static int switch_root_initramfs(void) {
+        if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0)
+                return log_error_errno(errno, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
+
+        if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0)
+                return log_error_errno(errno, "Failed to make /run/initramfs private mount: %m");
+
+        /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
+         * /run/initramfs/shutdown will take care of these.
+         * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
+         */
+        return switch_root("/run/initramfs", "/oldroot", false, MS_BIND);
+}
+
+
+int main(int argc, char *argv[]) {
+        bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
+        bool in_container, use_watchdog = false;
+        _cleanup_free_ char *cgroup = NULL;
+        char *arguments[3];
+        unsigned retries;
+        int cmd, r;
+        static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
+
+        log_parse_environment();
+        r = parse_argv(argc, argv);
+        if (r < 0)
+                goto error;
+
+        /* journald will die if not gone yet. The log target defaults
+         * to console, but may have been changed by command line options. */
+
+        log_close_console(); /* force reopen of /dev/console */
+        log_open();
+
+        umask(0022);
+
+        if (getpid() != 1) {
+                log_error("Not executed by init (PID 1).");
+                r = -EPERM;
+                goto error;
+        }
+
+        if (streq(arg_verb, "reboot"))
+                cmd = RB_AUTOBOOT;
+        else if (streq(arg_verb, "poweroff"))
+                cmd = RB_POWER_OFF;
+        else if (streq(arg_verb, "halt"))
+                cmd = RB_HALT_SYSTEM;
+        else if (streq(arg_verb, "kexec"))
+                cmd = LINUX_REBOOT_CMD_KEXEC;
+        else {
+                r = -EINVAL;
+                log_error("Unknown action '%s'.", arg_verb);
+                goto error;
+        }
+
+        cg_get_root_path(&cgroup);
+
+        use_watchdog = !!getenv("WATCHDOG_USEC");
+
+        /* lock us into memory */
+        mlockall(MCL_CURRENT|MCL_FUTURE);
+
+        log_info("Sending SIGTERM to remaining processes...");
+        broadcast_signal(SIGTERM, true, true);
+
+        log_info("Sending SIGKILL to remaining processes...");
+        broadcast_signal(SIGKILL, true, false);
+
+        in_container = detect_container(NULL) > 0;
+
+        need_umount = !in_container;
+        need_swapoff = !in_container;
+        need_loop_detach = !in_container;
+        need_dm_detach = !in_container;
+
+        /* Unmount all mountpoints, swaps, and loopback devices */
+        for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
+                bool changed = false;
+
+                if (use_watchdog)
+                        watchdog_ping();
+
+                /* Let's trim the cgroup tree on each iteration so
+                   that we leave an empty cgroup tree around, so that
+                   container managers get a nice notify event when we
+                   are down */
+                if (cgroup)
+                        cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
+
+                if (need_umount) {
+                        log_info("Unmounting file systems.");
+                        r = umount_all(&changed);
+                        if (r == 0) {
+                                need_umount = false;
+                                log_info("All filesystems unmounted.");
+                        } else if (r > 0)
+                                log_info("Not all file systems unmounted, %d left.", r);
+                        else
+                                log_error_errno(r, "Failed to unmount file systems: %m");
+                }
+
+                if (need_swapoff) {
+                        log_info("Deactivating swaps.");
+                        r = swapoff_all(&changed);
+                        if (r == 0) {
+                                need_swapoff = false;
+                                log_info("All swaps deactivated.");
+                        } else if (r > 0)
+                                log_info("Not all swaps deactivated, %d left.", r);
+                        else
+                                log_error_errno(r, "Failed to deactivate swaps: %m");
+                }
+
+                if (need_loop_detach) {
+                        log_info("Detaching loop devices.");
+                        r = loopback_detach_all(&changed);
+                        if (r == 0) {
+                                need_loop_detach = false;
+                                log_info("All loop devices detached.");
+                        } else if (r > 0)
+                                log_info("Not all loop devices detached, %d left.", r);
+                        else
+                                log_error_errno(r, "Failed to detach loop devices: %m");
+                }
+
+                if (need_dm_detach) {
+                        log_info("Detaching DM devices.");
+                        r = dm_detach_all(&changed);
+                        if (r == 0) {
+                                need_dm_detach = false;
+                                log_info("All DM devices detached.");
+                        } else if (r > 0)
+                                log_info("Not all DM devices detached, %d left.", r);
+                        else
+                                log_error_errno(r, "Failed to detach DM devices: %m");
+                }
+
+                if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
+                        if (retries > 0)
+                                log_info("All filesystems, swaps, loop devices, DM devices detached.");
+                        /* Yay, done */
+                        goto initrd_jump;
+                }
+
+                /* If in this iteration we didn't manage to
+                 * unmount/deactivate anything, we simply give up */
+                if (!changed) {
+                        log_info("Cannot finalize remaining%s%s%s%s continuing.",
+                                 need_umount ? " file systems," : "",
+                                 need_swapoff ? " swap devices," : "",
+                                 need_loop_detach ? " loop devices," : "",
+                                 need_dm_detach ? " DM devices," : "");
+                        goto initrd_jump;
+                }
+
+                log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
+                          retries + 1,
+                          need_umount ? " file systems," : "",
+                          need_swapoff ? " swap devices," : "",
+                          need_loop_detach ? " loop devices," : "",
+                          need_dm_detach ? " DM devices," : "");
+        }
+
+        log_error("Too many iterations, giving up.");
+
+ initrd_jump:
+
+        arguments[0] = NULL;
+        arguments[1] = arg_verb;
+        arguments[2] = NULL;
+        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
+
+        if (!in_container && !in_initrd() &&
+            access("/run/initramfs/shutdown", X_OK) == 0) {
+                r = switch_root_initramfs();
+                if (r >= 0) {
+                        argv[0] = (char*) "/shutdown";
+
+                        setsid();
+                        make_console_stdio();
+
+                        log_info("Successfully changed into root pivot.\n"
+                                 "Returning to initrd...");
+
+                        execv("/shutdown", argv);
+                        log_error_errno(errno, "Failed to execute shutdown binary: %m");
+                } else
+                        log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m");
+
+        }
+
+        if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
+                log_error("Failed to finalize %s%s%s%s ignoring",
+                          need_umount ? " file systems," : "",
+                          need_swapoff ? " swap devices," : "",
+                          need_loop_detach ? " loop devices," : "",
+                          need_dm_detach ? " DM devices," : "");
+
+        /* The kernel will automaticall flush ATA disks and suchlike
+         * on reboot(), but the file systems need to be synce'd
+         * explicitly in advance. So let's do this here, but not
+         * needlessly slow down containers. */
+        if (!in_container)
+                sync();
+
+        switch (cmd) {
+
+        case LINUX_REBOOT_CMD_KEXEC:
+
+                if (!in_container) {
+                        /* We cheat and exec kexec to avoid doing all its work */
+                        pid_t pid;
+
+                        log_info("Rebooting with kexec.");
+
+                        pid = fork();
+                        if (pid < 0)
+                                log_error_errno(errno, "Failed to fork: %m");
+                        else if (pid == 0) {
+
+                                const char * const args[] = {
+                                        KEXEC, "-e", NULL
+                                };
+
+                                /* Child */
+
+                                execv(args[0], (char * const *) args);
+                                _exit(EXIT_FAILURE);
+                        } else
+                                wait_for_terminate_and_warn("kexec", pid, true);
+                }
+
+                cmd = RB_AUTOBOOT;
+                /* Fall through */
+
+        case RB_AUTOBOOT:
+
+                if (!in_container) {
+                        _cleanup_free_ char *param = NULL;
+
+                        if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
+                                log_info("Rebooting with argument '%s'.", param);
+                                syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
+                        }
+                }
+
+                log_info("Rebooting.");
+                break;
+
+        case RB_POWER_OFF:
+                log_info("Powering off.");
+                break;
+
+        case RB_HALT_SYSTEM:
+                log_info("Halting system.");
+                break;
+
+        default:
+                assert_not_reached("Unknown magic");
+        }
+
+        reboot(cmd);
+        if (errno == EPERM && in_container) {
+                /* If we are in a container, and we lacked
+                 * CAP_SYS_BOOT just exit, this will kill our
+                 * container for good. */
+                log_info("Exiting container.");
+                exit(0);
+        }
+
+        log_error_errno(errno, "Failed to invoke reboot(): %m");
+        r = -errno;
+
+  error:
+        log_emergency_errno(r, "Critical error while doing system shutdown: %m");
+
+        freeze();
+}
diff --git a/src/power/shutdownd.c b/src/power/shutdownd.c
new file mode 100644
index 0000000..60a6468
--- /dev/null
+++ b/src/power/shutdownd.c
@@ -0,0 +1,461 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/socket.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/timerfd.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stddef.h>
+
+#include "systemd/sd-daemon.h"
+#include "systemd/sd-shutdown.h"
+
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+#include "utmp-wtmp.h"
+#include "mkdir.h"
+#include "fileio.h"
+
+union shutdown_buffer {
+        struct sd_shutdown_command command;
+        char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
+};
+
+static int read_packet(int fd, union shutdown_buffer *_b) {
+        struct ucred *ucred;
+        ssize_t n;
+
+        union shutdown_buffer b; /* We maintain our own copy here, in
+                                  * order not to corrupt the last message */
+        struct iovec iovec = {
+                .iov_base = &b,
+                .iov_len = sizeof(b) - 1,
+        };
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
+        } control = {};
+        struct msghdr msghdr = {
+                .msg_iov = &iovec,
+                .msg_iovlen = 1,
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
+        };
+
+        assert(fd >= 0);
+        assert(_b);
+
+        n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
+        if (n < 0) {
+                if (errno == EAGAIN || errno == EINTR)
+                        return 0;
+
+                log_error_errno(errno, "recvmsg(): %m");
+                return -errno;
+        }
+
+        cmsg_close_all(&msghdr);
+
+        if (n == 0) {
+                log_error("Short read");
+                return -EIO;
+        }
+
+        if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
+            control.cmsghdr.cmsg_level != SOL_SOCKET ||
+            control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
+            control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
+                log_warning("Received message without credentials. Ignoring.");
+                return 0;
+        }
+
+        ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
+        if (ucred->uid != 0) {
+                log_warning("Got request from unprivileged user. Ignoring.");
+                return 0;
+        }
+
+        if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
+                log_warning("Message has invalid size. Ignoring.");
+                return 0;
+        }
+
+        if (b.command.mode != SD_SHUTDOWN_NONE &&
+            b.command.mode != SD_SHUTDOWN_REBOOT &&
+            b.command.mode != SD_SHUTDOWN_POWEROFF &&
+            b.command.mode != SD_SHUTDOWN_HALT &&
+            b.command.mode != SD_SHUTDOWN_KEXEC) {
+                log_warning("Message has invalid mode. Ignoring.");
+                return 0;
+        }
+
+        b.space[n] = 0;
+
+        *_b = b;
+        return 1;
+}
+
+static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
+        char date[FORMAT_TIMESTAMP_MAX];
+        const char *prefix;
+        _cleanup_free_ char *l = NULL;
+
+        assert(c);
+        assert(c->warn_wall);
+
+        if (n >= c->usec)
+                return;
+
+        if (c->mode == SD_SHUTDOWN_HALT)
+                prefix = "The system is going down for system halt at ";
+        else if (c->mode == SD_SHUTDOWN_POWEROFF)
+                prefix = "The system is going down for power-off at ";
+        else if (c->mode == SD_SHUTDOWN_REBOOT)
+                prefix = "The system is going down for reboot at ";
+        else if (c->mode == SD_SHUTDOWN_KEXEC)
+                prefix = "The system is going down for kexec reboot at ";
+        else if (c->mode == SD_SHUTDOWN_NONE)
+                prefix = "The system shutdown has been cancelled at ";
+        else
+                assert_not_reached("Unknown mode!");
+
+        if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "",
+                     prefix, format_timestamp(date, sizeof(date), c->usec)) >= 0)
+                utmp_wall(l, NULL, NULL);
+        else
+                log_error("Failed to allocate wall message");
+}
+
+_const_ static usec_t when_wall(usec_t n, usec_t elapse) {
+
+        static const struct {
+                usec_t delay;
+                usec_t interval;
+        } table[] = {
+                { 0,                    USEC_PER_MINUTE      },
+                { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
+                { USEC_PER_HOUR,        30 * USEC_PER_MINUTE },
+                { 3 * USEC_PER_HOUR,    USEC_PER_HOUR        },
+        };
+
+        usec_t left, sub;
+        unsigned i = ELEMENTSOF(table) - 1;
+
+        /* If the time is already passed, then don't announce */
+        if (n >= elapse)
+                return 0;
+
+        left = elapse - n;
+        while (left < table[i].delay)
+                i--;
+        sub = (left / table[i].interval) * table[i].interval;
+
+        assert(sub < elapse);
+        return elapse - sub;
+}
+
+static usec_t when_nologin(usec_t elapse) {
+        return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
+}
+
+static const char *mode_to_string(enum sd_shutdown_mode m) {
+        switch (m) {
+        case SD_SHUTDOWN_REBOOT:
+                return "reboot";
+        case SD_SHUTDOWN_POWEROFF:
+                return "poweroff";
+        case SD_SHUTDOWN_HALT:
+                return "halt";
+        case SD_SHUTDOWN_KEXEC:
+                return "kexec";
+        default:
+                return NULL;
+        }
+}
+
+static int update_schedule_file(struct sd_shutdown_command *c) {
+        int r;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *t = NULL, *temp_path = NULL;
+
+        assert(c);
+
+        r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
+
+        t = cescape(c->wall_message);
+        if (!t)
+                return log_oom();
+
+        r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
+        if (r < 0)
+                return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
+
+        fchmod(fileno(f), 0644);
+
+        fprintf(f,
+                "USEC="USEC_FMT"\n"
+                "WARN_WALL=%i\n"
+                "MODE=%s\n",
+                c->usec,
+                c->warn_wall,
+                mode_to_string(c->mode));
+
+        if (c->dry_run)
+                fputs("DRY_RUN=1\n", f);
+
+        if (!isempty(t))
+                fprintf(f, "WALL_MESSAGE=%s\n", t);
+
+        fflush(f);
+
+        if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
+                log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
+                r = -errno;
+
+                unlink(temp_path);
+                unlink("/run/systemd/shutdown/scheduled");
+        }
+
+        return r;
+}
+
+static bool scheduled(struct sd_shutdown_command *c) {
+        return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
+}
+
+int main(int argc, char *argv[]) {
+        enum {
+                FD_SOCKET,
+                FD_WALL_TIMER,
+                FD_NOLOGIN_TIMER,
+                FD_SHUTDOWN_TIMER,
+                _FD_MAX
+        };
+
+        int r = EXIT_FAILURE, n_fds;
+        union shutdown_buffer b = {};
+        struct pollfd pollfd[_FD_MAX] = {};
+        bool exec_shutdown = false, unlink_nologin = false;
+        unsigned i;
+
+        if (getppid() != 1) {
+                log_error("This program should be invoked by init only.");
+                return EXIT_FAILURE;
+        }
+
+        if (argc > 1) {
+                log_error("This program does not take arguments.");
+                return EXIT_FAILURE;
+        }
+
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        umask(0022);
+
+        n_fds = sd_listen_fds(true);
+        if (n_fds < 0) {
+                log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
+                return EXIT_FAILURE;
+        }
+
+        if (n_fds != 1) {
+                log_error("Need exactly one file descriptor.");
+                return EXIT_FAILURE;
+        }
+
+        pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
+        pollfd[FD_SOCKET].events = POLLIN;
+
+        for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
+                pollfd[i].events = POLLIN;
+                pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+                if (pollfd[i].fd < 0) {
+                        log_error_errno(errno, "timerfd_create(): %m");
+                        goto finish;
+                }
+        }
+
+        log_debug("systemd-shutdownd running as pid "PID_FMT, getpid());
+
+        sd_notify(false,
+                  "READY=1\n"
+                  "STATUS=Processing requests...");
+
+        for (;;) {
+                int k;
+                usec_t n;
+
+                k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
+                if (k < 0) {
+
+                        if (errno == EAGAIN || errno == EINTR)
+                                continue;
+
+                        log_error_errno(errno, "poll(): %m");
+                        goto finish;
+                }
+
+                /* Exit on idle */
+                if (k == 0)
+                        break;
+
+                n = now(CLOCK_REALTIME);
+
+                if (pollfd[FD_SOCKET].revents) {
+
+                        k = read_packet(pollfd[FD_SOCKET].fd, &b);
+                        if (k < 0)
+                                goto finish;
+                        else if (k > 0) {
+                                struct itimerspec its;
+                                char date[FORMAT_TIMESTAMP_MAX];
+
+                                if (!scheduled(&b.command)) {
+                                        log_info("Shutdown canceled.");
+                                        if (b.command.warn_wall)
+                                                warn_wall(0, &b.command);
+                                        break;
+                                }
+
+                                zero(its);
+                                if (b.command.warn_wall) {
+                                        /* Send wall messages every so often */
+                                        timespec_store(&its.it_value, when_wall(n, b.command.usec));
+
+                                        /* Warn immediately if less than 15 minutes are left */
+                                        if (n < b.command.usec &&
+                                            n + 15*USEC_PER_MINUTE >= b.command.usec)
+                                                warn_wall(n, &b.command);
+                                }
+                                if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
+                                        log_error_errno(errno, "timerfd_settime(): %m");
+                                        goto finish;
+                                }
+
+                                /* Disallow logins 5 minutes prior to shutdown */
+                                zero(its);
+                                timespec_store(&its.it_value, when_nologin(b.command.usec));
+                                if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
+                                        log_error_errno(errno, "timerfd_settime(): %m");
+                                        goto finish;
+                                }
+
+                                /* Shutdown after the specified time is reached */
+                                zero(its);
+                                timespec_store(&its.it_value, b.command.usec);
+                                if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
+                                        log_error_errno(errno, "timerfd_settime(): %m");
+                                        goto finish;
+                                }
+
+                                update_schedule_file(&b.command);
+
+                                sd_notifyf(false,
+                                           "STATUS=Shutting down at %s (%s)...",
+                                           format_timestamp(date, sizeof(date), b.command.usec),
+                                           mode_to_string(b.command.mode));
+
+                                log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
+                        }
+                }
+
+                if (pollfd[FD_WALL_TIMER].revents) {
+                        struct itimerspec its = {};
+
+                        warn_wall(n, &b.command);
+                        flush_fd(pollfd[FD_WALL_TIMER].fd);
+
+                        /* Restart timer */
+                        timespec_store(&its.it_value, when_wall(n, b.command.usec));
+                        if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
+                                log_error_errno(errno, "timerfd_settime(): %m");
+                                goto finish;
+                        }
+                }
+
+                if (pollfd[FD_NOLOGIN_TIMER].revents) {
+                        int e;
+
+                        log_info("Creating /run/nologin, blocking further logins...");
+
+                        e = write_string_file_atomic("/run/nologin", "System is going down.");
+                        if (e < 0)
+                                log_error_errno(e, "Failed to create /run/nologin: %m");
+                        else
+                                unlink_nologin = true;
+
+                        flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
+                }
+
+                if (pollfd[FD_SHUTDOWN_TIMER].revents) {
+                        exec_shutdown = true;
+                        goto finish;
+                }
+        }
+
+        r = EXIT_SUCCESS;
+
+        log_debug("systemd-shutdownd stopped as pid "PID_FMT, getpid());
+
+finish:
+
+        for (i = 0; i < _FD_MAX; i++)
+                safe_close(pollfd[i].fd);
+
+        if (unlink_nologin)
+                unlink("/run/nologin");
+
+        unlink("/run/systemd/shutdown/scheduled");
+
+        if (exec_shutdown && !b.command.dry_run) {
+                char sw[3];
+
+                sw[0] = '-';
+                sw[1] = b.command.mode;
+                sw[2] = 0;
+
+                execl(SYSTEMCTL_BINARY_PATH,
+                      "shutdown",
+                      sw,
+                      "now",
+                      (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
+                      (b.command.warn_wall ? NULL : "--no-wall"),
+                      NULL);
+
+                log_error_errno(errno, "Failed to execute /sbin/shutdown: %m");
+        }
+
+        sd_notify(false,
+                  "STOPPING=\n"
+                  "STATUS=Exiting...");
+
+        return r;
+}
diff --git a/src/power/sleep.c b/src/power/sleep.c
new file mode 100644
index 0000000..cc1ffa6
--- /dev/null
+++ b/src/power/sleep.c
@@ -0,0 +1,219 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+  Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "sd-id128.h"
+#include "sd-messages.h"
+#include "log.h"
+#include "util.h"
+#include "strv.h"
+#include "fileio.h"
+#include "build.h"
+#include "sleep-config.h"
+#include "def.h"
+
+static char* arg_verb = NULL;
+
+static int write_mode(char **modes) {
+        int r = 0;
+        char **mode;
+
+        STRV_FOREACH(mode, modes) {
+                int k;
+
+                k = write_string_file("/sys/power/disk", *mode);
+                if (k == 0)
+                        return 0;
+
+                log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
+                                *mode);
+                if (r == 0)
+                        r = k;
+        }
+
+        if (r < 0)
+                log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
+
+        return r;
+}
+
+static int write_state(FILE **f, char **states) {
+        char **state;
+        int r = 0;
+
+        STRV_FOREACH(state, states) {
+                int k;
+
+                k = write_string_stream(*f, *state);
+                if (k == 0)
+                        return 0;
+                log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
+                                *state);
+                if (r == 0)
+                        r = k;
+
+                fclose(*f);
+                *f = fopen("/sys/power/state", "we");
+                if (!*f)
+                        return log_error_errno(errno, "Failed to open /sys/power/state: %m");
+        }
+
+        return r;
+}
+
+static int execute(char **modes, char **states) {
+
+        char *arguments[] = {
+                NULL,
+                (char*) "pre",
+                arg_verb,
+                NULL
+        };
+        static const char* const dirs[] = {SYSTEM_SLEEP_PATH, NULL};
+
+        int r;
+        _cleanup_fclose_ FILE *f = NULL;
+
+        /* This file is opened first, so that if we hit an error,
+         * we can abort before modifying any state. */
+        f = fopen("/sys/power/state", "we");
+        if (!f)
+                return log_error_errno(errno, "Failed to open /sys/power/state: %m");
+
+        /* Configure the hibernation mode */
+        r = write_mode(modes);
+        if (r < 0)
+                return r;
+
+        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
+
+        log_struct(LOG_INFO,
+                   LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
+                   LOG_MESSAGE("Suspending system..."),
+                   "SLEEP=%s", arg_verb,
+                   NULL);
+
+        r = write_state(&f, states);
+        if (r < 0)
+                return r;
+
+        log_struct(LOG_INFO,
+                   LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
+                   LOG_MESSAGE("System resumed."),
+                   "SLEEP=%s", arg_verb,
+                   NULL);
+
+        arguments[1] = (char*) "post";
+        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
+
+        return r;
+}
+
+static void help(void) {
+        printf("%s COMMAND\n\n"
+               "Suspend the system, hibernate the system, or both.\n\n"
+               "Commands:\n"
+               "  -h --help            Show this help and exit\n"
+               "  --version            Print version string and exit\n"
+               "  suspend              Suspend the system\n"
+               "  hibernate            Hibernate the system\n"
+               "  hybrid-sleep         Both hibernate and suspend the system\n"
+               , program_invocation_short_name);
+}
+
+static int parse_argv(int argc, char *argv[]) {
+        enum {
+                ARG_VERSION = 0x100,
+        };
+
+        static const struct option options[] = {
+                { "help",         no_argument,       NULL, 'h'           },
+                { "version",      no_argument,       NULL, ARG_VERSION   },
+                {}
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+                switch(c) {
+                case 'h':
+                        help();
+                        return 0; /* done */
+
+                case ARG_VERSION:
+                        puts(PACKAGE_STRING);
+                        puts(SYSTEMD_FEATURES);
+                        return 0 /* done */;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        if (argc - optind != 1) {
+                log_error("Usage: %s COMMAND",
+                          program_invocation_short_name);
+                return -EINVAL;
+        }
+
+        arg_verb = argv[optind];
+
+        if (!streq(arg_verb, "suspend") &&
+            !streq(arg_verb, "hibernate") &&
+            !streq(arg_verb, "hybrid-sleep")) {
+                log_error("Unknown command '%s'.", arg_verb);
+                return -EINVAL;
+        }
+
+        return 1 /* work to do */;
+}
+
+int main(int argc, char *argv[]) {
+        _cleanup_strv_free_ char **modes = NULL, **states = NULL;
+        int r;
+
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                goto finish;
+
+        r = parse_sleep_config(arg_verb, &modes, &states);
+        if (r < 0)
+                goto finish;
+
+        r = execute(modes, states);
+
+finish:
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/shutdownd/Makefile b/src/shutdownd/Makefile
deleted file mode 120000
index d0b0e8e..0000000
--- a/src/shutdownd/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile
\ No newline at end of file
diff --git a/src/shutdownd/shutdownd.c b/src/shutdownd/shutdownd.c
deleted file mode 100644
index 60a6468..0000000
--- a/src/shutdownd/shutdownd.c
+++ /dev/null
@@ -1,461 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/socket.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/timerfd.h>
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stddef.h>
-
-#include "systemd/sd-daemon.h"
-#include "systemd/sd-shutdown.h"
-
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-#include "utmp-wtmp.h"
-#include "mkdir.h"
-#include "fileio.h"
-
-union shutdown_buffer {
-        struct sd_shutdown_command command;
-        char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
-};
-
-static int read_packet(int fd, union shutdown_buffer *_b) {
-        struct ucred *ucred;
-        ssize_t n;
-
-        union shutdown_buffer b; /* We maintain our own copy here, in
-                                  * order not to corrupt the last message */
-        struct iovec iovec = {
-                .iov_base = &b,
-                .iov_len = sizeof(b) - 1,
-        };
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
-        } control = {};
-        struct msghdr msghdr = {
-                .msg_iov = &iovec,
-                .msg_iovlen = 1,
-                .msg_control = &control,
-                .msg_controllen = sizeof(control),
-        };
-
-        assert(fd >= 0);
-        assert(_b);
-
-        n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
-        if (n < 0) {
-                if (errno == EAGAIN || errno == EINTR)
-                        return 0;
-
-                log_error_errno(errno, "recvmsg(): %m");
-                return -errno;
-        }
-
-        cmsg_close_all(&msghdr);
-
-        if (n == 0) {
-                log_error("Short read");
-                return -EIO;
-        }
-
-        if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
-            control.cmsghdr.cmsg_level != SOL_SOCKET ||
-            control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
-            control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
-                log_warning("Received message without credentials. Ignoring.");
-                return 0;
-        }
-
-        ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
-        if (ucred->uid != 0) {
-                log_warning("Got request from unprivileged user. Ignoring.");
-                return 0;
-        }
-
-        if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
-                log_warning("Message has invalid size. Ignoring.");
-                return 0;
-        }
-
-        if (b.command.mode != SD_SHUTDOWN_NONE &&
-            b.command.mode != SD_SHUTDOWN_REBOOT &&
-            b.command.mode != SD_SHUTDOWN_POWEROFF &&
-            b.command.mode != SD_SHUTDOWN_HALT &&
-            b.command.mode != SD_SHUTDOWN_KEXEC) {
-                log_warning("Message has invalid mode. Ignoring.");
-                return 0;
-        }
-
-        b.space[n] = 0;
-
-        *_b = b;
-        return 1;
-}
-
-static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
-        char date[FORMAT_TIMESTAMP_MAX];
-        const char *prefix;
-        _cleanup_free_ char *l = NULL;
-
-        assert(c);
-        assert(c->warn_wall);
-
-        if (n >= c->usec)
-                return;
-
-        if (c->mode == SD_SHUTDOWN_HALT)
-                prefix = "The system is going down for system halt at ";
-        else if (c->mode == SD_SHUTDOWN_POWEROFF)
-                prefix = "The system is going down for power-off at ";
-        else if (c->mode == SD_SHUTDOWN_REBOOT)
-                prefix = "The system is going down for reboot at ";
-        else if (c->mode == SD_SHUTDOWN_KEXEC)
-                prefix = "The system is going down for kexec reboot at ";
-        else if (c->mode == SD_SHUTDOWN_NONE)
-                prefix = "The system shutdown has been cancelled at ";
-        else
-                assert_not_reached("Unknown mode!");
-
-        if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "",
-                     prefix, format_timestamp(date, sizeof(date), c->usec)) >= 0)
-                utmp_wall(l, NULL, NULL);
-        else
-                log_error("Failed to allocate wall message");
-}
-
-_const_ static usec_t when_wall(usec_t n, usec_t elapse) {
-
-        static const struct {
-                usec_t delay;
-                usec_t interval;
-        } table[] = {
-                { 0,                    USEC_PER_MINUTE      },
-                { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
-                { USEC_PER_HOUR,        30 * USEC_PER_MINUTE },
-                { 3 * USEC_PER_HOUR,    USEC_PER_HOUR        },
-        };
-
-        usec_t left, sub;
-        unsigned i = ELEMENTSOF(table) - 1;
-
-        /* If the time is already passed, then don't announce */
-        if (n >= elapse)
-                return 0;
-
-        left = elapse - n;
-        while (left < table[i].delay)
-                i--;
-        sub = (left / table[i].interval) * table[i].interval;
-
-        assert(sub < elapse);
-        return elapse - sub;
-}
-
-static usec_t when_nologin(usec_t elapse) {
-        return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
-}
-
-static const char *mode_to_string(enum sd_shutdown_mode m) {
-        switch (m) {
-        case SD_SHUTDOWN_REBOOT:
-                return "reboot";
-        case SD_SHUTDOWN_POWEROFF:
-                return "poweroff";
-        case SD_SHUTDOWN_HALT:
-                return "halt";
-        case SD_SHUTDOWN_KEXEC:
-                return "kexec";
-        default:
-                return NULL;
-        }
-}
-
-static int update_schedule_file(struct sd_shutdown_command *c) {
-        int r;
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *t = NULL, *temp_path = NULL;
-
-        assert(c);
-
-        r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
-        if (r < 0)
-                return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
-
-        t = cescape(c->wall_message);
-        if (!t)
-                return log_oom();
-
-        r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
-        if (r < 0)
-                return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
-
-        fchmod(fileno(f), 0644);
-
-        fprintf(f,
-                "USEC="USEC_FMT"\n"
-                "WARN_WALL=%i\n"
-                "MODE=%s\n",
-                c->usec,
-                c->warn_wall,
-                mode_to_string(c->mode));
-
-        if (c->dry_run)
-                fputs("DRY_RUN=1\n", f);
-
-        if (!isempty(t))
-                fprintf(f, "WALL_MESSAGE=%s\n", t);
-
-        fflush(f);
-
-        if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
-                log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
-                r = -errno;
-
-                unlink(temp_path);
-                unlink("/run/systemd/shutdown/scheduled");
-        }
-
-        return r;
-}
-
-static bool scheduled(struct sd_shutdown_command *c) {
-        return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
-}
-
-int main(int argc, char *argv[]) {
-        enum {
-                FD_SOCKET,
-                FD_WALL_TIMER,
-                FD_NOLOGIN_TIMER,
-                FD_SHUTDOWN_TIMER,
-                _FD_MAX
-        };
-
-        int r = EXIT_FAILURE, n_fds;
-        union shutdown_buffer b = {};
-        struct pollfd pollfd[_FD_MAX] = {};
-        bool exec_shutdown = false, unlink_nologin = false;
-        unsigned i;
-
-        if (getppid() != 1) {
-                log_error("This program should be invoked by init only.");
-                return EXIT_FAILURE;
-        }
-
-        if (argc > 1) {
-                log_error("This program does not take arguments.");
-                return EXIT_FAILURE;
-        }
-
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
-
-        umask(0022);
-
-        n_fds = sd_listen_fds(true);
-        if (n_fds < 0) {
-                log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
-                return EXIT_FAILURE;
-        }
-
-        if (n_fds != 1) {
-                log_error("Need exactly one file descriptor.");
-                return EXIT_FAILURE;
-        }
-
-        pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
-        pollfd[FD_SOCKET].events = POLLIN;
-
-        for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
-                pollfd[i].events = POLLIN;
-                pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
-                if (pollfd[i].fd < 0) {
-                        log_error_errno(errno, "timerfd_create(): %m");
-                        goto finish;
-                }
-        }
-
-        log_debug("systemd-shutdownd running as pid "PID_FMT, getpid());
-
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Processing requests...");
-
-        for (;;) {
-                int k;
-                usec_t n;
-
-                k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
-                if (k < 0) {
-
-                        if (errno == EAGAIN || errno == EINTR)
-                                continue;
-
-                        log_error_errno(errno, "poll(): %m");
-                        goto finish;
-                }
-
-                /* Exit on idle */
-                if (k == 0)
-                        break;
-
-                n = now(CLOCK_REALTIME);
-
-                if (pollfd[FD_SOCKET].revents) {
-
-                        k = read_packet(pollfd[FD_SOCKET].fd, &b);
-                        if (k < 0)
-                                goto finish;
-                        else if (k > 0) {
-                                struct itimerspec its;
-                                char date[FORMAT_TIMESTAMP_MAX];
-
-                                if (!scheduled(&b.command)) {
-                                        log_info("Shutdown canceled.");
-                                        if (b.command.warn_wall)
-                                                warn_wall(0, &b.command);
-                                        break;
-                                }
-
-                                zero(its);
-                                if (b.command.warn_wall) {
-                                        /* Send wall messages every so often */
-                                        timespec_store(&its.it_value, when_wall(n, b.command.usec));
-
-                                        /* Warn immediately if less than 15 minutes are left */
-                                        if (n < b.command.usec &&
-                                            n + 15*USEC_PER_MINUTE >= b.command.usec)
-                                                warn_wall(n, &b.command);
-                                }
-                                if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
-                                        log_error_errno(errno, "timerfd_settime(): %m");
-                                        goto finish;
-                                }
-
-                                /* Disallow logins 5 minutes prior to shutdown */
-                                zero(its);
-                                timespec_store(&its.it_value, when_nologin(b.command.usec));
-                                if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
-                                        log_error_errno(errno, "timerfd_settime(): %m");
-                                        goto finish;
-                                }
-
-                                /* Shutdown after the specified time is reached */
-                                zero(its);
-                                timespec_store(&its.it_value, b.command.usec);
-                                if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
-                                        log_error_errno(errno, "timerfd_settime(): %m");
-                                        goto finish;
-                                }
-
-                                update_schedule_file(&b.command);
-
-                                sd_notifyf(false,
-                                           "STATUS=Shutting down at %s (%s)...",
-                                           format_timestamp(date, sizeof(date), b.command.usec),
-                                           mode_to_string(b.command.mode));
-
-                                log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
-                        }
-                }
-
-                if (pollfd[FD_WALL_TIMER].revents) {
-                        struct itimerspec its = {};
-
-                        warn_wall(n, &b.command);
-                        flush_fd(pollfd[FD_WALL_TIMER].fd);
-
-                        /* Restart timer */
-                        timespec_store(&its.it_value, when_wall(n, b.command.usec));
-                        if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
-                                log_error_errno(errno, "timerfd_settime(): %m");
-                                goto finish;
-                        }
-                }
-
-                if (pollfd[FD_NOLOGIN_TIMER].revents) {
-                        int e;
-
-                        log_info("Creating /run/nologin, blocking further logins...");
-
-                        e = write_string_file_atomic("/run/nologin", "System is going down.");
-                        if (e < 0)
-                                log_error_errno(e, "Failed to create /run/nologin: %m");
-                        else
-                                unlink_nologin = true;
-
-                        flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
-                }
-
-                if (pollfd[FD_SHUTDOWN_TIMER].revents) {
-                        exec_shutdown = true;
-                        goto finish;
-                }
-        }
-
-        r = EXIT_SUCCESS;
-
-        log_debug("systemd-shutdownd stopped as pid "PID_FMT, getpid());
-
-finish:
-
-        for (i = 0; i < _FD_MAX; i++)
-                safe_close(pollfd[i].fd);
-
-        if (unlink_nologin)
-                unlink("/run/nologin");
-
-        unlink("/run/systemd/shutdown/scheduled");
-
-        if (exec_shutdown && !b.command.dry_run) {
-                char sw[3];
-
-                sw[0] = '-';
-                sw[1] = b.command.mode;
-                sw[2] = 0;
-
-                execl(SYSTEMCTL_BINARY_PATH,
-                      "shutdown",
-                      sw,
-                      "now",
-                      (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
-                      (b.command.warn_wall ? NULL : "--no-wall"),
-                      NULL);
-
-                log_error_errno(errno, "Failed to execute /sbin/shutdown: %m");
-        }
-
-        sd_notify(false,
-                  "STOPPING=\n"
-                  "STATUS=Exiting...");
-
-        return r;
-}
diff --git a/src/sleep/Makefile b/src/sleep/Makefile
deleted file mode 120000
index d0b0e8e..0000000
--- a/src/sleep/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile
\ No newline at end of file
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
deleted file mode 100644
index cc1ffa6..0000000
--- a/src/sleep/sleep.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2012 Lennart Poettering
-  Copyright 2013 Zbigniew Jędrzejewski-Szmek
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-
-#include "sd-id128.h"
-#include "sd-messages.h"
-#include "log.h"
-#include "util.h"
-#include "strv.h"
-#include "fileio.h"
-#include "build.h"
-#include "sleep-config.h"
-#include "def.h"
-
-static char* arg_verb = NULL;
-
-static int write_mode(char **modes) {
-        int r = 0;
-        char **mode;
-
-        STRV_FOREACH(mode, modes) {
-                int k;
-
-                k = write_string_file("/sys/power/disk", *mode);
-                if (k == 0)
-                        return 0;
-
-                log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
-                                *mode);
-                if (r == 0)
-                        r = k;
-        }
-
-        if (r < 0)
-                log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
-
-        return r;
-}
-
-static int write_state(FILE **f, char **states) {
-        char **state;
-        int r = 0;
-
-        STRV_FOREACH(state, states) {
-                int k;
-
-                k = write_string_stream(*f, *state);
-                if (k == 0)
-                        return 0;
-                log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
-                                *state);
-                if (r == 0)
-                        r = k;
-
-                fclose(*f);
-                *f = fopen("/sys/power/state", "we");
-                if (!*f)
-                        return log_error_errno(errno, "Failed to open /sys/power/state: %m");
-        }
-
-        return r;
-}
-
-static int execute(char **modes, char **states) {
-
-        char *arguments[] = {
-                NULL,
-                (char*) "pre",
-                arg_verb,
-                NULL
-        };
-        static const char* const dirs[] = {SYSTEM_SLEEP_PATH, NULL};
-
-        int r;
-        _cleanup_fclose_ FILE *f = NULL;
-
-        /* This file is opened first, so that if we hit an error,
-         * we can abort before modifying any state. */
-        f = fopen("/sys/power/state", "we");
-        if (!f)
-                return log_error_errno(errno, "Failed to open /sys/power/state: %m");
-
-        /* Configure the hibernation mode */
-        r = write_mode(modes);
-        if (r < 0)
-                return r;
-
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
-
-        log_struct(LOG_INFO,
-                   LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
-                   LOG_MESSAGE("Suspending system..."),
-                   "SLEEP=%s", arg_verb,
-                   NULL);
-
-        r = write_state(&f, states);
-        if (r < 0)
-                return r;
-
-        log_struct(LOG_INFO,
-                   LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
-                   LOG_MESSAGE("System resumed."),
-                   "SLEEP=%s", arg_verb,
-                   NULL);
-
-        arguments[1] = (char*) "post";
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
-
-        return r;
-}
-
-static void help(void) {
-        printf("%s COMMAND\n\n"
-               "Suspend the system, hibernate the system, or both.\n\n"
-               "Commands:\n"
-               "  -h --help            Show this help and exit\n"
-               "  --version            Print version string and exit\n"
-               "  suspend              Suspend the system\n"
-               "  hibernate            Hibernate the system\n"
-               "  hybrid-sleep         Both hibernate and suspend the system\n"
-               , program_invocation_short_name);
-}
-
-static int parse_argv(int argc, char *argv[]) {
-        enum {
-                ARG_VERSION = 0x100,
-        };
-
-        static const struct option options[] = {
-                { "help",         no_argument,       NULL, 'h'           },
-                { "version",      no_argument,       NULL, ARG_VERSION   },
-                {}
-        };
-
-        int c;
-
-        assert(argc >= 0);
-        assert(argv);
-
-        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
-                switch(c) {
-                case 'h':
-                        help();
-                        return 0; /* done */
-
-                case ARG_VERSION:
-                        puts(PACKAGE_STRING);
-                        puts(SYSTEMD_FEATURES);
-                        return 0 /* done */;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        assert_not_reached("Unhandled option");
-                }
-
-        if (argc - optind != 1) {
-                log_error("Usage: %s COMMAND",
-                          program_invocation_short_name);
-                return -EINVAL;
-        }
-
-        arg_verb = argv[optind];
-
-        if (!streq(arg_verb, "suspend") &&
-            !streq(arg_verb, "hibernate") &&
-            !streq(arg_verb, "hybrid-sleep")) {
-                log_error("Unknown command '%s'.", arg_verb);
-                return -EINVAL;
-        }
-
-        return 1 /* work to do */;
-}
-
-int main(int argc, char *argv[]) {
-        _cleanup_strv_free_ char **modes = NULL, **states = NULL;
-        int r;
-
-        log_set_target(LOG_TARGET_AUTO);
-        log_parse_environment();
-        log_open();
-
-        r = parse_argv(argc, argv);
-        if (r <= 0)
-                goto finish;
-
-        r = parse_sleep_config(arg_verb, &modes, &states);
-        if (r < 0)
-                goto finish;
-
-        r = execute(modes, states);
-
-finish:
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
-- 
2.2.1.209.g41e5f3a



More information about the systemd-devel mailing list