chiark / gitweb /
loginctl: implement more verbs
[elogind.git] / src / systemctl.c
index 00db47f125dcd0b0abca95326d487f205509f773..840e2ffc2d2f235b61983378c298b4265db54524 100644 (file)
@@ -33,7 +33,6 @@
 #include <sys/stat.h>
 #include <stddef.h>
 #include <sys/prctl.h>
-
 #include <dbus/dbus.h>
 
 #include "log.h"
@@ -56,6 +55,7 @@
 #include "bus-errors.h"
 #include "build.h"
 #include "unit-name.h"
+#include "pager.h"
 
 static const char *arg_type = NULL;
 static char **arg_property = NULL;
@@ -81,6 +81,7 @@ static char **arg_wall = NULL;
 static const char *arg_kill_who = NULL;
 static const char *arg_kill_mode = NULL;
 static int arg_signal = SIGTERM;
+static const char *arg_root = NULL;
 static usec_t arg_when = 0;
 static enum action {
         ACTION_INVALID,
@@ -117,11 +118,9 @@ static const char *arg_host = NULL;
 
 static bool private_bus = false;
 
-static pid_t pager_pid = 0;
 static pid_t agent_pid = 0;
 
 static int daemon_reload(DBusConnection *bus, char **args, unsigned n);
-static void pager_open(void);
 
 static bool on_tty(void) {
         static int t = -1;
@@ -138,6 +137,13 @@ static bool on_tty(void) {
         return t;
 }
 
+static void pager_open_if_enabled(void) {
+        on_tty();
+
+        if (!arg_no_pager)
+                pager_open();
+}
+
 static void spawn_ask_password_agent(void) {
         pid_t parent;
 
@@ -273,22 +279,6 @@ static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
         return EXIT_FAILURE;
 }
 
-static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
-
-        assert(iter);
-        assert(data);
-
-        if (dbus_message_iter_get_arg_type(iter) != type)
-                return -EIO;
-
-        dbus_message_iter_get_basic(iter, data);
-
-        if (!dbus_message_iter_next(iter) != !next)
-                return -EIO;
-
-        return 0;
-}
-
 static void warn_wall(enum action action) {
         static const char *table[_ACTION_MAX] = {
                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
@@ -474,7 +464,7 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
 
         assert(bus);
 
-        pager_open();
+        pager_open_if_enabled();
 
         if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
@@ -795,7 +785,7 @@ static int dot(DBusConnection *bus, char **args, unsigned n) {
                  "                 red       = Conflicts\n"
                  "                 green     = After\n");
 
-        if (isatty(fileno(stdout)))
+        if (on_tty())
                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
 
@@ -824,7 +814,7 @@ static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
 
         assert(bus);
 
-        pager_open();
+        pager_open_if_enabled();
 
         if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
@@ -851,7 +841,7 @@ static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_message_iter_recurse(&iter, &sub);
 
-        if (isatty(STDOUT_FILENO))
+        if (on_tty())
                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
 
         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
@@ -887,7 +877,7 @@ static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
                 dbus_message_iter_next(&sub);
         }
 
-        if (isatty(STDOUT_FILENO))
+        if (on_tty())
                 printf("\n%u jobs listed.\n", k);
 
         r = 0;
@@ -1565,6 +1555,7 @@ static int check_unit(DBusConnection *bus, char **args, unsigned n) {
 
                         dbus_error_free(&error);
                         dbus_message_unref(m);
+                        m = NULL;
                         continue;
                 }
 
@@ -1735,7 +1726,7 @@ static void exec_status_info_free(ExecStatusInfo *i) {
 }
 
 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
-        uint64_t start_timestamp, exit_timestamp;
+        uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
         DBusMessageIter sub2, sub3;
         const char*path;
         unsigned n;
@@ -1789,7 +1780,9 @@ static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i)
         if (!dbus_message_iter_next(&sub2) ||
             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
+            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
+            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
@@ -2087,6 +2080,10 @@ static void print_status_info(UnitStatusInfo *i) {
 
 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
 
+        assert(name);
+        assert(iter);
+        assert(i);
+
         switch (dbus_message_iter_get_arg_type(iter)) {
 
         case DBUS_TYPE_STRING: {
@@ -2094,7 +2091,7 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
 
                 dbus_message_iter_get_basic(iter, &s);
 
-                if (s[0]) {
+                if (!isempty(s)) {
                         if (streq(name, "Id"))
                                 i->id = s;
                         else if (streq(name, "LoadState"))
@@ -2253,74 +2250,6 @@ static int print_property(const char *name, DBusMessageIter *iter) {
 
         switch (dbus_message_iter_get_arg_type(iter)) {
 
-        case DBUS_TYPE_STRING: {
-                const char *s;
-                dbus_message_iter_get_basic(iter, &s);
-
-                if (arg_all || s[0])
-                        printf("%s=%s\n", name, s);
-
-                return 0;
-        }
-
-        case DBUS_TYPE_BOOLEAN: {
-                dbus_bool_t b;
-                dbus_message_iter_get_basic(iter, &b);
-                printf("%s=%s\n", name, yes_no(b));
-
-                return 0;
-        }
-
-        case DBUS_TYPE_UINT64: {
-                uint64_t u;
-                dbus_message_iter_get_basic(iter, &u);
-
-                /* Yes, heuristics! But we can change this check
-                 * should it turn out to not be sufficient */
-
-                if (strstr(name, "Timestamp")) {
-                        char timestamp[FORMAT_TIMESTAMP_MAX], *t;
-
-                        if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
-                                printf("%s=%s\n", name, strempty(t));
-                } else if (strstr(name, "USec")) {
-                        char timespan[FORMAT_TIMESPAN_MAX];
-
-                        printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
-                } else
-                        printf("%s=%llu\n", name, (unsigned long long) u);
-
-                return 0;
-        }
-
-        case DBUS_TYPE_UINT32: {
-                uint32_t u;
-                dbus_message_iter_get_basic(iter, &u);
-
-                if (strstr(name, "UMask") || strstr(name, "Mode"))
-                        printf("%s=%04o\n", name, u);
-                else
-                        printf("%s=%u\n", name, (unsigned) u);
-
-                return 0;
-        }
-
-        case DBUS_TYPE_INT32: {
-                int32_t i;
-                dbus_message_iter_get_basic(iter, &i);
-
-                printf("%s=%i\n", name, (int) i);
-                return 0;
-        }
-
-        case DBUS_TYPE_DOUBLE: {
-                double d;
-                dbus_message_iter_get_basic(iter, &d);
-
-                printf("%s=%g\n", name, d);
-                return 0;
-        }
-
         case DBUS_TYPE_STRUCT: {
                 DBusMessageIter sub;
                 dbus_message_iter_recurse(iter, &sub);
@@ -2352,55 +2281,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
 
         case DBUS_TYPE_ARRAY:
 
-                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
-                        DBusMessageIter sub;
-                        bool space = false;
-
-                        dbus_message_iter_recurse(iter, &sub);
-                        if (arg_all ||
-                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                                printf("%s=", name);
-
-                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                                        const char *s;
-
-                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
-                                        dbus_message_iter_get_basic(&sub, &s);
-                                        printf("%s%s", space ? " " : "", s);
-
-                                        space = true;
-                                        dbus_message_iter_next(&sub);
-                                }
-
-                                puts("");
-                        }
-
-                        return 0;
-
-                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
-                        DBusMessageIter sub;
-
-                        dbus_message_iter_recurse(iter, &sub);
-                        if (arg_all ||
-                            dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                                printf("%s=", name);
-
-                                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
-                                        uint8_t u;
-
-                                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
-                                        dbus_message_iter_get_basic(&sub, &u);
-                                        printf("%02x", u);
-
-                                        dbus_message_iter_next(&sub);
-                                }
-
-                                puts("");
-                        }
-
-                        return 0;
-
-                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
+                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
                         DBusMessageIter sub, sub2;
 
                         dbus_message_iter_recurse(iter, &sub);
@@ -2505,6 +2386,9 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                 break;
         }
 
+        if (generic_print_property(name, iter, arg_all) > 0)
+                return 0;
+
         if (arg_all)
                 printf("%s=[unprintable]\n", name);
 
@@ -2648,7 +2532,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
         show_properties = !streq(args[0], "status");
 
         if (show_properties)
-                pager_open();
+                pager_open_if_enabled();
 
         if (show_properties && n <= 1) {
                 /* If not argument is specified inspect the manager
@@ -3044,7 +2928,7 @@ static int dump(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_error_init(&error);
 
-        pager_open();
+        pager_open_if_enabled();
 
         if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
@@ -3321,6 +3205,13 @@ static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
                         goto finish;
                 }
 
+                if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
+                        /* On reexecution, we expect a disconnect, not
+                         * a reply */
+                        r = 0;
+                        goto finish;
+                }
+
                 log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
@@ -3408,7 +3299,7 @@ static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_error_init(&error);
 
-        pager_open();
+        pager_open_if_enabled();
 
         if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
@@ -3838,8 +3729,14 @@ static int remove_marked_symlinks(const char *config_path) {
         return r;
 }
 
-static int create_symlink(const char *verb, const char *old_path, const char *new_path) {
+static int create_symlink(const char *verb, const char *orig_old_path, const char *new_path) {
         int r;
+       const char *old_path;
+
+       if (arg_root)
+               old_path = orig_old_path+strlen(arg_root);
+       else
+               old_path = orig_old_path;
 
         assert(old_path);
         assert(new_path);
@@ -3953,6 +3850,7 @@ static int create_symlink(const char *verb, const char *old_path, const char *ne
                         return 1;
                 }
 
+                free(dest);
                 return 0;
         }
 
@@ -4051,12 +3949,23 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
 
         STRV_FOREACH(p, paths->unit_path) {
                 int fd;
+               char *path, *should_free;
+
+               if (arg_root)
+                       should_free = path = strappend(arg_root, *p);
+               else {
+                       should_free = NULL;
+                       path = *p;
+               }
 
-                if (!(filename = path_make_absolute(i->name, *p))) {
+                if (!(filename = path_make_absolute(i->name, path))) {
                         log_error("Out of memory");
                         return -ENOMEM;
                 }
 
+               if (should_free)
+                       free(should_free);
+
                 /* Ensure that we don't follow symlinks */
                 if ((fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOCTTY)) >= 0)
                         if ((f = fdopen(fd, "re")))
@@ -4079,7 +3988,7 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
         }
 
         if (!f) {
-#if (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)) && defined (HAVE_SYSV_COMPAT)
+#if (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX)) && defined (HAVE_SYSV_COMPAT)
 
                 if (endswith(i->name, ".service")) {
                         char *sysv;
@@ -4091,7 +4000,14 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
                         }
 
                         sysv[strlen(sysv) - sizeof(".service") + 1] = 0;
-                        exists = access(sysv, F_OK) >= 0;
+                        if (arg_root) {
+                                char *tmp_path;
+
+                                tmp_path = strappend (arg_root, sysv);
+                                exists = access (tmp_path, F_OK) >= 0;
+                                free (tmp_path);
+                       } else
+                                exists = access(sysv, F_OK) >= 0;
 
                         if (exists) {
                                 pid_t pid;
@@ -4101,6 +4017,7 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
                                         "/sbin/chkconfig",
                                         NULL,
                                         NULL,
+                                        NULL,
                                         NULL
                                 };
 
@@ -4110,8 +4027,10 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
                                 argv[2] =
                                         streq(verb, "enable") ? "on" :
                                         streq(verb, "disable") ? "off" : "--level=5";
+                                if (arg_root)
+                                        argv[3] = strappend("--root=", arg_root);
 
-                                log_info("Executing %s %s %s", argv[0], argv[1], strempty(argv[2]));
+                               log_info("Executing %s %s %s %s", argv[0], argv[1], strempty(argv[2]), strempty(argv[3]));
 
                                 if ((pid = fork()) < 0) {
                                         log_error("Failed to fork: %m");
@@ -4157,6 +4076,16 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
                 return r;
         }
 
+        /* Consider unit files stored in /lib and /usr always enabled
+         * if they have no [Install] data. */
+        if (streq(verb, "is-enabled") &&
+            strv_isempty(i->aliases) &&
+            strv_isempty(i->wanted_by) &&
+            !path_startswith(filename, "/etc")) {
+                fclose(f);
+                return 1;
+        }
+
         n_symlinks += strv_length(i->aliases);
         n_symlinks += strv_length(i->wanted_by);
 
@@ -4178,20 +4107,24 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
 }
 
 static char *get_config_path(void) {
+        char *ret;
 
         if (arg_user && arg_global)
-                return strdup(USER_CONFIG_UNIT_PATH);
+                ret = strdup(USER_CONFIG_UNIT_PATH);
 
         if (arg_user) {
-                char *p;
-
-                if (user_config_home(&p) < 0)
+                if (user_config_home(&ret) < 0)
                         return NULL;
-
-                return p;
         }
 
-        return strdup(SYSTEM_CONFIG_UNIT_PATH);
+        ret = strdup(SYSTEM_CONFIG_UNIT_PATH);
+        if (arg_root) {
+                char *p;
+                p = strappend (arg_root, ret);
+                free (ret);
+                return p;
+        } else
+                return ret;
 }
 
 static int enable_unit(DBusConnection *bus, char **args, unsigned n) {
@@ -4274,7 +4207,7 @@ static int enable_unit(DBusConnection *bus, char **args, unsigned n) {
                     /* Don't try to reload anything if we are called for system changes but the system wasn't booted with systemd */
                     (arg_user || sd_booted() > 0) &&
                     /* Don't try to reload anything if we are running in a chroot environment */
-                    (arg_user || running_in_chroot() <= 0) ) {
+                    (arg_user || running_in_chroot() <= 0 || arg_root) ) {
                         int q;
 
                         if ((q = daemon_reload(bus, args, n)) < 0)
@@ -4310,10 +4243,9 @@ static int systemctl_help(void) {
                "                      pending\n"
                "     --ignore-dependencies\n"
                "                      When queueing a new job, ignore all its dependencies\n"
-               "     --kill-mode=MODE How to send signal\n"
                "     --kill-who=WHO   Who to send signal to\n"
                "  -s --signal=SIGNAL  Which signal to send\n"
-               "  -H --host=[user@]host\n"
+               "  -H --host=[USER@]HOST\n"
                "                      Show information for remote host\n"
                "  -P --privileged     Acquire privileges before execution\n"
                "  -q --quiet          Suppress output\n"
@@ -4321,11 +4253,12 @@ static int systemctl_help(void) {
                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
                "                      configuration\n"
-               "     --no-pager       Do not pipe output into a pager.\n"
+               "     --no-pager       Do not pipe output into a pager\n"
                "     --no-ask-password\n"
                "                      Do not ask for system passwords\n"
                "     --order          When generating graph for dot, show only order\n"
                "     --require        When generating graph for dot, show only requirement\n"
+               "     --root=path      Use <root> as the root file system\n"
                "     --system         Connect to system manager\n"
                "     --user           Connect to user service manager\n"
                "     --global         Enable/disable unit files globally\n"
@@ -4460,6 +4393,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_NO_WALL,
                 ARG_ORDER,
                 ARG_REQUIRE,
+                ARG_ROOT,
                 ARG_FULL,
                 ARG_NO_RELOAD,
                 ARG_DEFAULTS,
@@ -4488,10 +4422,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "quiet",     no_argument,       NULL, 'q'           },
                 { "order",     no_argument,       NULL, ARG_ORDER     },
                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
+                { "root",      required_argument, NULL, ARG_ROOT      },
                 { "force",     no_argument,       NULL, 'f'           },
                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
                 { "defaults",  no_argument,       NULL, ARG_DEFAULTS  },
-                { "kill-mode", required_argument, NULL, ARG_KILL_MODE },
+                { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
                 { "signal",    required_argument, NULL, 's'           },
                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
@@ -4582,6 +4517,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_dot = DOT_REQUIRE;
                         break;
 
+                case ARG_ROOT:
+                        arg_root = optarg;
+                        break;
+
                 case ARG_FULL:
                         arg_full = true;
                         break;
@@ -4755,10 +4694,10 @@ static int parse_time_spec(const char *t, usec_t *_u) {
 
         if (streq(t, "now"))
                 *_u = 0;
-        else if (t[0] == '+') {
+        else if (!strchr(t, ':')) {
                 uint64_t u;
 
-                if (safe_atou64(t + 1, &u) < 0)
+                if (safe_atou64(t, &u) < 0)
                         return -EINVAL;
 
                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
@@ -5362,7 +5301,7 @@ 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, bool warn, const char *message) {
+static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
         int fd = -1;
         struct msghdr msghdr;
         struct iovec iovec;
@@ -5372,6 +5311,7 @@ static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) {
         zero(c);
         c.elapse = t;
         c.mode = mode;
+        c.dry_run = dry_run;
         c.warn_wall = warn;
 
         if (message)
@@ -5467,6 +5407,7 @@ static int halt_main(DBusConnection *bus) {
                                    arg_action == ACTION_HALT     ? 'H' :
                                    arg_action == ACTION_POWEROFF ? 'P' :
                                                                    'r',
+                                   arg_dry,
                                    !arg_no_wall,
                                    m);
                 free(m);
@@ -5540,96 +5481,6 @@ static int runlevel_main(void) {
         return 0;
 }
 
-static void pager_open(void) {
-        int fd[2];
-        const char *pager;
-        pid_t parent_pid;
-
-        if (pager_pid > 0)
-                return;
-
-        if (!on_tty() || arg_no_pager)
-                return;
-
-        if ((pager = getenv("PAGER")))
-                if (!*pager || streq(pager, "cat"))
-                        return;
-
-        /* Determine and cache number of columns before we spawn the
-         * pager so that we get the value from the actual tty */
-        columns();
-
-        if (pipe(fd) < 0) {
-                log_error("Failed to create pager pipe: %m");
-                return;
-        }
-
-        parent_pid = getpid();
-
-        pager_pid = fork();
-        if (pager_pid < 0) {
-                log_error("Failed to fork pager: %m");
-                close_pipe(fd);
-                return;
-        }
-
-        /* In the child start the pager */
-        if (pager_pid == 0) {
-
-                dup2(fd[0], STDIN_FILENO);
-                close_pipe(fd);
-
-                setenv("LESS", "FRSX", 0);
-
-                /* Make sure the pager goes away when the parent dies */
-                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
-                        _exit(EXIT_FAILURE);
-
-                /* Check whether our parent died before we were able
-                 * to set the death signal */
-                if (getppid() != parent_pid)
-                        _exit(EXIT_SUCCESS);
-
-                if (pager) {
-                        execlp(pager, pager, NULL);
-                        execl("/bin/sh", "sh", "-c", pager, NULL);
-                } else {
-                        /* Debian's alternatives command for pagers is
-                         * called 'pager'. Note that we do not call
-                         * sensible-pagers here, since that is just a
-                         * shell script that implements a logic that
-                         * is similar to this one anyway, but is
-                         * Debian-specific. */
-                        execlp("pager", "pager", NULL);
-
-                        execlp("less", "less", NULL);
-                        execlp("more", "more", NULL);
-                }
-
-                log_error("Unable to execute pager: %m");
-                _exit(EXIT_FAILURE);
-        }
-
-        /* Return in the parent */
-        if (dup2(fd[1], STDOUT_FILENO) < 0)
-                log_error("Failed to duplicate pager pipe: %m");
-
-        close_pipe(fd);
-}
-
-static void pager_close(void) {
-        siginfo_t dummy;
-
-        if (pager_pid <= 0)
-                return;
-
-        /* Inform pager that we are done */
-        fclose(stdout);
-        kill(pager_pid, SIGCONT);
-        wait_for_terminate(pager_pid, &dummy);
-        pager_pid = 0;
-}
-
 static void agent_close(void) {
         siginfo_t dummy;
 
@@ -5714,7 +5565,7 @@ int main(int argc, char*argv[]) {
                 break;
 
         case ACTION_CANCEL_SHUTDOWN:
-                r = send_shutdownd(0, 0, false, NULL);
+                r = send_shutdownd(0, 0, false, false, NULL);
                 break;
 
         case ACTION_INVALID: