[systemd-commits] .gitignore Makefile.am src/manager.c src/shutdownd.c src/shutdownd.h src/socket-util.h src/systemctl.c src/util.c src/util.h units/.gitignore units/systemd-initctl.socket units/systemd-logger.service.in units/systemd-logger.socket units/systemd-shutdownd.service.in units/systemd-shutdownd.socket

Lennart Poettering lennart at kemper.freedesktop.org
Mon Aug 16 06:38:04 PDT 2010


 .gitignore                         |    1 
 Makefile.am                        |   19 ++
 src/manager.c                      |    2 
 src/shutdownd.c                    |  272 +++++++++++++++++++++++++++++++++++++
 src/shutdownd.h                    |   35 ++++
 src/socket-util.h                  |   16 +-
 src/systemctl.c                    |  160 ++++++++++++++++++++-
 src/util.c                         |   11 +
 src/util.h                         |    2 
 units/.gitignore                   |    1 
 units/systemd-initctl.socket       |    1 
 units/systemd-logger.service.in    |    1 
 units/systemd-logger.socket        |    3 
 units/systemd-shutdownd.service.in |   15 ++
 units/systemd-shutdownd.socket     |   16 ++
 15 files changed, 534 insertions(+), 21 deletions(-)

New commits:
commit f61448083198dc0e4e0d19a916bcd478336cc85d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Aug 16 15:37:52 2010 +0200

    systemctl: add support for delayed shutdown, similar to sysv in style

diff --git a/.gitignore b/.gitignore
index f01db0a..6b8edf5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+systemd-shutdownd
 systemd-random-seed
 systemd-update-utmp
 test-env-replace
diff --git a/Makefile.am b/Makefile.am
index 384778e..07204a9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -71,7 +71,8 @@ rootlibexec_PROGRAMS = \
 	systemd-cgroups-agent \
 	systemd-initctl \
 	systemd-update-utmp \
-	systemd-random-seed
+	systemd-random-seed \
+	systemd-shutdownd
 
 noinst_PROGRAMS = \
 	test-engine \
@@ -137,6 +138,7 @@ dist_systemunit_DATA = \
 	units/dbus.target \
 	units/systemd-initctl.socket \
 	units/systemd-logger.socket \
+	units/systemd-shutdownd.socket \
 	units/dev-hugepages.automount \
 	units/dev-hugepages.mount \
 	units/dev-mqueue.automount \
@@ -161,6 +163,7 @@ nodist_systemunit_DATA = \
 	units/multi-user.target \
 	units/systemd-initctl.service \
 	units/systemd-logger.service \
+	units/systemd-shutdownd.service \
 	units/systemd-update-utmp-runlevel.service \
 	units/systemd-update-utmp-shutdown.service \
 	units/systemd-random-seed-save.service \
@@ -182,6 +185,7 @@ EXTRA_DIST = \
 	units/remote-fs.target.m4 \
 	units/systemd-initctl.service.in \
 	units/systemd-logger.service.in \
+	units/systemd-shutdownd.service.in \
 	units/systemd-update-utmp-runlevel.service.in \
 	units/systemd-update-utmp-shutdown.service.in \
 	units/systemd-random-seed-save.service.in \
@@ -346,7 +350,8 @@ EXTRA_DIST += \
 	src/bus-errors.h \
 	src/cgroup-show.h \
 	src/utmp-wtmp.h \
-	src/build.h
+	src/build.h \
+	src/shutdownd.h
 
 MANPAGES = \
 	man/systemd.1 \
@@ -529,6 +534,16 @@ systemd_random_seed_CFLAGS = \
 systemd_random_seed_LDADD = \
 	libsystemd-basic.la
 
+systemd_shutdownd_SOURCES = \
+	src/sd-daemon.c \
+	src/shutdownd.c
+
+systemd_shutdownd_CFLAGS = \
+	$(AM_CFLAGS)
+
+systemd_shutdownd_LDADD = \
+	libsystemd-basic.la
+
 systemd_cgroups_agent_SOURCES = \
 	src/cgroups-agent.c \
 	src/dbus-common.c
diff --git a/src/manager.c b/src/manager.c
index 4e8ddfb..c8fdbb5 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -1786,7 +1786,7 @@ static int manager_process_notify_fd(Manager *m) {
                         if (n >= 0)
                                 return -EIO;
 
-                        if (errno == EAGAIN)
+                        if (errno == EAGAIN || errno == EINTR)
                                 break;
 
                         return -errno;
diff --git a/src/shutdownd.c b/src/shutdownd.c
new file mode 100644
index 0000000..241c432
--- /dev/null
+++ b/src/shutdownd.c
@@ -0,0 +1,272 @@
+/*-*- 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 General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/socket.h>
+#include <sys/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 "shutdownd.h"
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+#include "sd-daemon.h"
+
+static int read_packet(int fd, struct shutdownd_command *_c) {
+        struct msghdr msghdr;
+        struct iovec iovec;
+        struct ucred *ucred;
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
+        } control;
+        struct shutdownd_command c;
+        ssize_t n;
+
+        assert(fd >= 0);
+        assert(_c);
+
+        zero(iovec);
+        iovec.iov_base = &c;
+        iovec.iov_len = sizeof(c);
+
+        zero(control);
+        zero(msghdr);
+        msghdr.msg_iov = &iovec;
+        msghdr.msg_iovlen = 1;
+        msghdr.msg_control = &control;
+        msghdr.msg_controllen = sizeof(control);
+
+        if ((n = recvmsg(fd, &msghdr, MSG_DONTWAIT)) <= 0) {
+                if (n >= 0) {
+                        log_error("Short read");
+                        return -EIO;
+                }
+
+                if (errno == EAGAIN || errno == EINTR)
+                        return 0;
+
+                log_error("recvmsg(): %m");
+                return -errno;
+        }
+
+        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 (n != sizeof(c)) {
+                log_warning("Message has invaliud size. Ignoring");
+                return 0;
+        }
+
+        *_c = c;
+        return 1;
+}
+
+int main(int argc, char *argv[]) {
+        enum {
+                FD_SOCKET,
+                FD_SHUTDOWN_TIMER,
+                FD_NOLOGIN_TIMER,
+                _FD_MAX
+        };
+
+        int r = 4, n;
+        int one = 1;
+        unsigned n_fds = 1;
+        struct shutdownd_command c;
+        struct pollfd pollfd[_FD_MAX];
+        bool exec_shutdown = false, unlink_nologin = false;
+
+        if (getppid() != 1) {
+                log_error("This program should be invoked by init only.");
+                return 1;
+        }
+
+        if (argc > 1) {
+                log_error("This program does not take arguments.");
+                return 1;
+        }
+
+        log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+        log_parse_environment();
+
+        if ((n = sd_listen_fds(true)) < 0) {
+                log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
+                return 1;
+        }
+
+        if (n != 1) {
+                log_error("Need exactly one file descriptor.");
+                return 2;
+        }
+
+        if (setsockopt(SD_LISTEN_FDS_START, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
+                log_error("SO_PASSCRED failed: %m");
+                return 3;
+        }
+
+        zero(c);
+        zero(pollfd);
+
+        pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
+        pollfd[FD_SOCKET].events = POLLIN;
+        pollfd[FD_SHUTDOWN_TIMER].fd = -1;
+        pollfd[FD_SHUTDOWN_TIMER].events = POLLIN;
+        pollfd[FD_NOLOGIN_TIMER].fd = -1;
+        pollfd[FD_NOLOGIN_TIMER].events = POLLIN;
+
+        log_debug("systemd-shutdownd running as pid %lu", (unsigned long) getpid());
+
+        sd_notify(false,
+                  "READY=1\n"
+                  "STATUS=Processing requests...");
+
+        do {
+                int k;
+
+                if (poll(pollfd, n_fds, -1) < 0) {
+
+                        if (errno == EAGAIN || errno == EINTR)
+                                continue;
+
+                        log_error("poll(): %m");
+                        goto finish;
+                }
+
+                if (pollfd[FD_SOCKET].revents) {
+
+                        if ((k = read_packet(pollfd[FD_SOCKET].fd, &c)) < 0)
+                                goto finish;
+                        else if (k > 0 && c.elapse > 0) {
+                                struct itimerspec its;
+                                char buf[27];
+
+                                if (pollfd[FD_SHUTDOWN_TIMER].fd < 0)
+                                        if ((pollfd[FD_SHUTDOWN_TIMER].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
+                                                log_error("timerfd_create(): %m");
+                                                goto finish;
+                                        }
+
+                                if (pollfd[FD_NOLOGIN_TIMER].fd < 0)
+                                        if ((pollfd[FD_NOLOGIN_TIMER].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
+                                                log_error("timerfd_create(): %m");
+                                                goto finish;
+                                        }
+
+                                /* Disallow logins 5 minutes prior to shutdown */
+                                zero(its);
+                                timespec_store(&its.it_value, c.elapse > 5*USEC_PER_MINUTE ? c.elapse - 5*USEC_PER_MINUTE : 0);
+                                if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
+                                        log_error("timerfd_settime(): %m");
+                                        goto finish;
+                                }
+
+                                /* Shutdown after the specified time is reached */
+                                zero(its);
+                                timespec_store(&its.it_value, c.elapse);
+                                if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
+                                        log_error("timerfd_settime(): %m");
+                                        goto finish;
+                                }
+
+                                n_fds = 3;
+
+                                ctime_r(&its.it_value.tv_sec, buf);
+
+                                sd_notifyf(false,
+                                           "STATUS=Shutting down at %s...",
+                                           strstrip(buf));
+                        }
+                }
+
+                if (pollfd[FD_NOLOGIN_TIMER].fd >= 0 &&
+                    pollfd[FD_NOLOGIN_TIMER].revents) {
+                        int e;
+
+                        if ((e = touch("/etc/nologin")) < 0)
+                                log_error("Failed to create /etc/nologin: %s", strerror(-e));
+                        else
+                                unlink_nologin = true;
+
+                        /* Disarm nologin timer */
+                        close_nointr_nofail(pollfd[FD_NOLOGIN_TIMER].fd);
+                        pollfd[FD_NOLOGIN_TIMER].fd = -1;
+                        n_fds = 2;
+
+                }
+
+                if (pollfd[FD_SHUTDOWN_TIMER].fd >= 0 &&
+                    pollfd[FD_SHUTDOWN_TIMER].revents) {
+                        exec_shutdown = true;
+                        goto finish;
+                }
+
+        } while (c.elapse > 0);
+
+        r = 0;
+
+        log_debug("systemd-shutdownd stopped as pid %lu", (unsigned long) getpid());
+
+finish:
+        if (pollfd[FD_SOCKET].fd >= 0)
+                close_nointr_nofail(pollfd[FD_SOCKET].fd);
+
+        if (pollfd[FD_SHUTDOWN_TIMER].fd >= 0)
+                close_nointr_nofail(pollfd[FD_SHUTDOWN_TIMER].fd);
+
+        if (pollfd[FD_NOLOGIN_TIMER].fd >= 0)
+                close_nointr_nofail(pollfd[FD_NOLOGIN_TIMER].fd);
+
+        if (exec_shutdown) {
+                char sw[3];
+
+                sw[0] = '-';
+                sw[1] = c.mode;
+                sw[2] = 0;
+
+                execl(SYSTEMCTL_BINARY_PATH, "shutdown", sw, "now", NULL);
+                log_error("Failed to execute /sbin/shutdown: %m");
+        }
+
+        if (unlink_nologin)
+                unlink("/etc/nologin");
+
+        sd_notify(false,
+                  "STATUS=Exiting...");
+
+        return r;
+}
diff --git a/src/shutdownd.h b/src/shutdownd.h
new file mode 100644
index 0000000..d298b01
--- /dev/null
+++ b/src/shutdownd.h
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooshutdowndhfoo
+#define fooshutdowndhfoo
+
+/***
+  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 General Public License as published by
+  the Free Software Foundation; either version 2 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "macro.h"
+
+_packed_ struct shutdownd_command {
+        usec_t elapse;
+        char mode; /* H, P, r, i.e. the switches usually passed to
+                    * shutdown to select whether to halt, power-off or
+                    * reboot the machine */
+};
+
+#endif
diff --git a/src/socket-util.h b/src/socket-util.h
index 86c9e47..b5cb2a8 100644
--- a/src/socket-util.h
+++ b/src/socket-util.h
@@ -30,14 +30,16 @@
 #include "macro.h"
 #include "util.h"
 
+union sockaddr_union {
+        struct sockaddr sa;
+        struct sockaddr_in in4;
+        struct sockaddr_in6 in6;
+        struct sockaddr_un un;
+        struct sockaddr_storage storage;
+};
+
 typedef struct SocketAddress {
-        union {
-                struct sockaddr sa;
-                struct sockaddr_in in4;
-                struct sockaddr_in6 in6;
-                struct sockaddr_un un;
-                struct sockaddr_storage storage;
-        } sockaddr;
+        union sockaddr_union sockaddr;
 
         /* We store the size here explicitly due to the weird
          * sockaddr_un semantics for abstract sockets */
diff --git a/src/systemctl.c b/src/systemctl.c
index baae019..e517031 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -49,6 +49,7 @@
 #include "path-lookup.h"
 #include "conf-parser.h"
 #include "sd-daemon.h"
+#include "shutdownd.h"
 
 static const char *arg_type = NULL;
 static char **arg_property = NULL;
@@ -68,6 +69,9 @@ static bool arg_full = false;
 static bool arg_force = false;
 static bool arg_defaults = false;
 static char **arg_wall = NULL;
+static usec_t arg_when = 0;
+static bool arg_skip_fsck = false;
+static bool arg_force_fsck = false;
 static enum action {
         ACTION_INVALID,
         ACTION_SYSTEMCTL,
@@ -84,6 +88,7 @@ static enum action {
         ACTION_RELOAD,
         ACTION_REEXEC,
         ACTION_RUNLEVEL,
+        ACTION_CANCEL_SHUTDOWN,
         _ACTION_MAX
 } arg_action = ACTION_SYSTEMCTL;
 static enum dot {
@@ -3832,7 +3837,10 @@ static int shutdown_help(void) {
                "  -r --reboot    Reboot the machine\n"
                "  -h             Equivalent to --poweroff, overriden by --halt\n"
                "  -k             Don't halt/power-off/reboot, just send warnings\n"
-               "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
+               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
+               "  -f             Skip fsck on reboot\n"
+               "  -F             Force fsck on reboot\n"
+               "  -c             Cancel a pending shutdown\n",
                program_invocation_short_name);
 
         return 0;
@@ -4099,6 +4107,53 @@ static int halt_parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
+static int parse_time_spec(const char *t, usec_t *_u) {
+        assert(t);
+        assert(_u);
+
+        if (streq(t, "now"))
+                *_u = 0;
+        else if (t[0] == '+') {
+                uint64_t u;
+
+                if (safe_atou64(t + 1, &u) < 0)
+                        return -EINVAL;
+
+                *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
+        } else {
+                char *e = NULL;
+                long hour, minute;
+                struct tm tm;
+                time_t s;
+                usec_t n;
+
+                errno = 0;
+                hour = strtol(t, &e, 10);
+                if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
+                        return -EINVAL;
+
+                minute = strtol(e+1, &e, 10);
+                if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
+                        return -EINVAL;
+
+                n = now(CLOCK_REALTIME);
+                s = (time_t) n / USEC_PER_SEC;
+                assert_se(localtime_r(&s, &tm));
+
+                tm.tm_hour = (int) hour;
+                tm.tm_min = (int) minute;
+
+                assert_se(s = mktime(&tm));
+
+                *_u = (usec_t) s * USEC_PER_SEC;
+
+                while (*_u <= n)
+                        *_u += USEC_PER_DAY;
+        }
+
+        return 0;
+}
+
 static int shutdown_parse_argv(int argc, char *argv[]) {
 
         enum {
@@ -4115,12 +4170,12 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                 { NULL,        0,                 NULL, 0           }
         };
 
-        int c;
+        int c, r;
 
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
                 switch (c) {
 
                 case ARG_HELP:
@@ -4157,6 +4212,18 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                         /* Compatibility nops */
                         break;
 
+                case 'f':
+                        arg_skip_fsck = true;
+                        break;
+
+                case 'F':
+                        arg_force_fsck = true;
+                        break;
+
+                case 'c':
+                        arg_action = ACTION_CANCEL_SHUTDOWN;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -4166,10 +4233,13 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                 }
         }
 
-        if (argc > optind && !streq(argv[optind], "now"))
-                log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
+        if (argc > optind)
+                if ((r = parse_time_spec(argv[optind], &arg_when)) < 0) {
+                        log_error("Failed to parse time specification: %s", argv[optind]);
+                        return r;
+                }
 
-        /* We ignore the time argument */
+        /* We skip the time argument */
         if (argc > optind + 1)
                 arg_wall = argv + optind + 1;
 
@@ -4624,6 +4694,62 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
         return verbs[i].dispatch(bus, argv + optind, left);
 }
 
+static int send_shutdownd(usec_t t, char mode) {
+        int fd = -1;
+        struct msghdr msghdr;
+        struct iovec iovec;
+        union sockaddr_union sockaddr;
+        struct ucred *ucred;
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
+        } control;
+        struct shutdownd_command c;
+
+        zero(c);
+        c.elapse = t;
+        c.mode = mode;
+
+        if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0)
+                return -errno;
+
+        zero(sockaddr);
+        sockaddr.sa.sa_family = AF_UNIX;
+        sockaddr.un.sun_path[0] = 0;
+        strncpy(sockaddr.un.sun_path+1, "/org/freedesktop/systemd1/shutdownd", sizeof(sockaddr.un.sun_path)-1);
+
+        zero(iovec);
+        iovec.iov_base = (char*) &c;
+        iovec.iov_len = sizeof(c);
+
+        zero(control);
+        control.cmsghdr.cmsg_level = SOL_SOCKET;
+        control.cmsghdr.cmsg_type = SCM_CREDENTIALS;
+        control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred));
+
+        ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
+        ucred->pid = getpid();
+        ucred->uid = getuid();
+        ucred->gid = getgid();
+
+        zero(msghdr);
+        msghdr.msg_name = &sockaddr;
+        msghdr.msg_namelen = sizeof(sa_family_t) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
+
+        msghdr.msg_iov = &iovec;
+        msghdr.msg_iovlen = 1;
+        msghdr.msg_control = &control;
+        msghdr.msg_controllen = control.cmsghdr.cmsg_len;
+
+        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        close_nointr_nofail(fd);
+        return 0;
+}
+
 static int reload_with_fallback(DBusConnection *bus) {
 
         if (bus) {
@@ -4677,6 +4803,24 @@ static int halt_main(DBusConnection *bus) {
                 return -EPERM;
         }
 
+        if (arg_force_fsck) {
+                if ((r = touch("/forcefsck")) < 0)
+                        log_warning("Failed to create /forcefsck: %s", strerror(-r));
+        } else if (arg_skip_fsck) {
+                if ((r = touch("/fastboot")) < 0)
+                        log_warning("Failed to create /fastboot: %s", strerror(-r));
+        }
+
+        if (arg_when > 0) {
+                if ((r = send_shutdownd(arg_when,
+                                        arg_action == ACTION_HALT ? 'H' :
+                                        arg_action == ACTION_POWEROFF ? 'P' :
+                                        'r')) < 0)
+                        log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
+                else
+                        return 0;
+        }
+
         if (!arg_dry && !arg_immediate)
                 return start_with_fallback(bus);
 
@@ -4790,6 +4934,10 @@ int main(int argc, char*argv[]) {
                 retval = reload_with_fallback(bus) < 0;
                 break;
 
+        case ACTION_CANCEL_SHUTDOWN:
+                retval = send_shutdownd(0, 0) < 0;
+                break;
+
         case ACTION_INVALID:
         case ACTION_RUNLEVEL:
         default:
diff --git a/src/util.c b/src/util.c
index c0b63dd..bc227f5 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2997,6 +2997,17 @@ void nss_disable_nscd(void) {
                 log_debug("Cannot disable nscd.");
 }
 
+int touch(const char *path) {
+        int fd;
+
+        assert(path);
+
+        if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666)) < 0)
+                return -errno;
+
+        close_nointr_nofail(fd);
+        return 0;
+}
 
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
diff --git a/src/util.h b/src/util.h
index 66ebb46..e9126c0 100644
--- a/src/util.h
+++ b/src/util.h
@@ -338,6 +338,8 @@ char *ellipsize(const char *s, unsigned length, unsigned percent);
 
 void nss_disable_nscd(void);
 
+int touch(const char *path);
+
 const char *ioprio_class_to_string(int i);
 int ioprio_class_from_string(const char *s);
 
diff --git a/units/.gitignore b/units/.gitignore
index 0318e48..9ac3401 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -1,3 +1,4 @@
+systemd-shutdownd.service
 systemd-random-seed-load.service
 systemd-random-seed-save.service
 systemd-initctl.service
diff --git a/units/systemd-initctl.socket b/units/systemd-initctl.socket
index 3db2683..bcb54b3 100644
--- a/units/systemd-initctl.socket
+++ b/units/systemd-initctl.socket
@@ -10,7 +10,6 @@
 [Unit]
 Description=systemd /dev/initctl Compatibility Socket
 DefaultDependencies=no
-After=sysinit.target
 Before=sockets.target
 
 [Socket]
diff --git a/units/systemd-logger.service.in b/units/systemd-logger.service.in
index 2a9ec21..2004438 100644
--- a/units/systemd-logger.service.in
+++ b/units/systemd-logger.service.in
@@ -9,7 +9,6 @@
 
 [Unit]
 Description=systemd Logging Daemon
-DefaultDependencies=no
 After=@SPECIAL_SYSLOG_SERVICE@
 
 [Service]
diff --git a/units/systemd-logger.socket b/units/systemd-logger.socket
index 57a590d..f62b582 100644
--- a/units/systemd-logger.socket
+++ b/units/systemd-logger.socket
@@ -9,9 +9,6 @@
 
 [Unit]
 Description=systemd Logging Socket
-DefaultDependencies=no
-After=sysinit.target
-Before=sockets.target
 
 [Socket]
 ListenStream=@/org/freedesktop/systemd1/logger
diff --git a/units/systemd-shutdownd.service.in b/units/systemd-shutdownd.service.in
new file mode 100644
index 0000000..5d0bd77
--- /dev/null
+++ b/units/systemd-shutdownd.service.in
@@ -0,0 +1,15 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=systemd Shutdown Daemon
+DefaultDependencies=no
+
+[Service]
+ExecStart=@rootlibexecdir@/systemd-shutdownd
diff --git a/units/systemd-shutdownd.socket b/units/systemd-shutdownd.socket
new file mode 100644
index 0000000..9a95fa9
--- /dev/null
+++ b/units/systemd-shutdownd.socket
@@ -0,0 +1,16 @@
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+
+# See systemd.special(7) for details
+
+[Unit]
+Description=systemd Shutdown Socket
+DefaultDependencies=no
+Before=sockets.target
+
+[Socket]
+ListenStream=@/org/freedesktop/systemd1/shutdownd


More information about the systemd-commits mailing list