]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/systemctl/systemctl.c
tree-wide: drop {} from one-line if blocks
[thirdparty/systemd.git] / src / systemctl / systemctl.c
index 4e702fb8bc13f09bf6422b2cdbf896dad70e803d..a82b9b83a2356ad9939c544f16bd2cecbef7f6ca 100644 (file)
@@ -34,7 +34,6 @@
 #include <stddef.h>
 
 #include "sd-daemon.h"
-#include "sd-shutdown.h"
 #include "sd-login.h"
 #include "sd-bus.h"
 #include "log.h"
@@ -72,6 +71,8 @@
 #include "formats-util.h"
 #include "process-util.h"
 #include "terminal-util.h"
+#include "hostname-util.h"
+#include "signal-util.h"
 
 static char **arg_types = NULL;
 static char **arg_states = NULL;
@@ -137,6 +138,7 @@ static unsigned arg_lines = 10;
 static OutputMode arg_output = OUTPUT_SHORT;
 static bool arg_plain = false;
 static bool arg_firmware_setup = false;
+static bool arg_now = false;
 
 static bool original_stdout_is_tty;
 
@@ -251,7 +253,7 @@ static void warn_wall(enum action a) {
                 }
 
                 if (*p) {
-                        utmp_wall(p, NULL, NULL);
+                        utmp_wall(p, NULL, NULL, NULL, NULL);
                         return;
                 }
         }
@@ -259,7 +261,7 @@ static void warn_wall(enum action a) {
         if (!table[a])
                 return;
 
-        utmp_wall(table[a], NULL, NULL);
+        utmp_wall(table[a], NULL, NULL, NULL, NULL);
 }
 
 static bool avoid_bus(void) {
@@ -533,10 +535,8 @@ static int get_unit_list(
                 return bus_log_create_error(r);
 
         r = sd_bus_call(bus, m, 0, &error, &reply);
-        if (r < 0) {
-                log_error("Failed to list units: %s", bus_error_message(&error, r));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
 
         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
         if (r < 0)
@@ -603,7 +603,7 @@ static int get_unit_list_recursive(
         r = set_put(replies, reply);
         if (r < 0) {
                 sd_bus_message_unref(reply);
-                return r;
+                return log_oom();
         }
 
         if (arg_recursive) {
@@ -612,15 +612,15 @@ static int get_unit_list_recursive(
 
                 r = sd_get_machine_names(&machines);
                 if (r < 0)
-                        return r;
+                        return log_error_errno(r, "Failed to get machine names: %m");
 
                 STRV_FOREACH(i, machines) {
-                        _cleanup_bus_close_unref_ sd_bus *container = NULL;
+                        _cleanup_bus_flush_close_unref_ sd_bus *container = NULL;
                         int k;
 
                         r = sd_bus_open_system_machine(&container, *i);
                         if (r < 0) {
-                                log_error_errno(r, "Failed to connect to container %s: %m", *i);
+                                log_warning_errno(r, "Failed to connect to container %s, ignoring: %m", *i);
                                 continue;
                         }
 
@@ -633,7 +633,7 @@ static int get_unit_list_recursive(
                         r = set_put(replies, reply);
                         if (r < 0) {
                                 sd_bus_message_unref(reply);
-                                return r;
+                                return log_oom();
                         }
                 }
 
@@ -1181,7 +1181,7 @@ static int list_timers(sd_bus *bus, char **args) {
 
         for (u = unit_infos; u < unit_infos + n; u++) {
                 _cleanup_strv_free_ char **triggered = NULL;
-                dual_timestamp next = {};
+                dual_timestamp next = DUAL_TIMESTAMP_NULL;
                 usec_t m, last = 0;
 
                 if (!endswith(u->id, ".timer"))
@@ -1472,6 +1472,7 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
                                        "Requisite\0"
                                        "RequisiteOverridable\0"
                                        "Wants\0"
+                                       "ConsistsOf\0"
                                        "BindsTo\0",
                 [DEPENDENCY_REVERSE] = "RequiredBy\0"
                                        "RequiredByOverridable\0"
@@ -1637,13 +1638,15 @@ static int list_dependencies(sd_bus *bus, char **args) {
         _cleanup_strv_free_ char **units = NULL;
         _cleanup_free_ char *unit = NULL;
         const char *u;
+        int r;
 
         assert(bus);
 
         if (args[1]) {
-                unit = unit_name_mangle(args[1], MANGLE_NOGLOB);
-                if (!unit)
-                        return log_oom();
+                r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &unit);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle unit name: %m");
+
                 u = unit;
         } else
                 u = SPECIAL_DEFAULT_TARGET;
@@ -1674,17 +1677,23 @@ static const struct bus_properties_map machine_info_property_map[] = {
         {}
 };
 
+static void machine_info_clear(struct machine_info *info) {
+        if (info) {
+                free(info->name);
+                free(info->state);
+                free(info->control_group);
+                zero(*info);
+        }
+}
+
 static void free_machines_list(struct machine_info *machine_infos, int n) {
         int i;
 
         if (!machine_infos)
                 return;
 
-        for (i = 0; i < n; i++) {
-                free(machine_infos[i].name);
-                free(machine_infos[i].state);
-                free(machine_infos[i].control_group);
-        }
+        for (i = 0; i < n; i++)
+                machine_info_clear(&machine_infos[i]);
 
         free(machine_infos);
 }
@@ -1699,7 +1708,7 @@ static int compare_machine_info(const void *a, const void *b) {
 }
 
 static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
-        _cleanup_bus_close_unref_ sd_bus *container = NULL;
+        _cleanup_bus_flush_close_unref_ sd_bus *container = NULL;
         int r;
 
         assert(mi);
@@ -1733,7 +1742,7 @@ static int get_machine_list(
         _cleanup_free_ char *hn = NULL;
         size_t sz = 0;
         char **i;
-        int c = 0;
+        int c = 0, r;
 
         hn = gethostname_malloc();
         if (!hn)
@@ -1751,7 +1760,10 @@ static int get_machine_list(
                 c++;
         }
 
-        sd_get_machine_names(&m);
+        r = sd_get_machine_names(&m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get machine list: %m");
+
         STRV_FOREACH(i, m) {
                 _cleanup_free_ char *class = NULL;
 
@@ -1939,9 +1951,9 @@ static int set_default(sd_bus *bus, char **args) {
         unsigned n_changes = 0;
         int r;
 
-        unit = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
-        if (!unit)
-                return log_oom();
+        r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         if (!bus || avoid_bus()) {
                 r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
@@ -1972,7 +1984,7 @@ static int set_default(sd_bus *bus, char **args) {
                         return r;
                 }
 
-                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
                 if (r < 0)
                         return r;
 
@@ -2258,7 +2270,7 @@ static int unit_find_paths(
         assert(fragment_path);
         assert(lp);
 
-        if (!avoid_bus_cache && !unit_name_is_template(unit_name)) {
+        if (!avoid_bus_cache && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL;
                 _cleanup_free_ char *unit = NULL;
@@ -2324,24 +2336,23 @@ static int unit_find_paths(
 
                 names = set_new(NULL);
                 if (!names)
-                        return -ENOMEM;
+                        return log_oom();
 
                 r = set_put(names, unit_name);
                 if (r < 0)
-                        return r;
+                        return log_error_errno(r, "Failed to add unit name: %m");
 
                 r = unit_file_find_path(lp, unit_name, &path);
                 if (r < 0)
                         return r;
 
                 if (r == 0) {
-                        _cleanup_free_ char *template;
-
-                        template = unit_name_template(unit_name);
-                        if (!template)
-                                return log_oom();
+                        _cleanup_free_ char *template = NULL;
 
-                        if (!streq(template, unit_name)) {
+                        r = unit_name_template(unit_name, &template);
+                        if (r < 0 && r != -EINVAL)
+                                return log_error_errno(r, "Failed to determine template name: %m");
+                        if (r >= 0) {
                                 r = unit_file_find_path(lp, template, &path);
                                 if (r < 0)
                                         return r;
@@ -2383,9 +2394,9 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states
 
         assert(name);
 
-        n = unit_name_mangle(name, MANGLE_NOGLOB);
-        if (!n)
-                return log_oom();
+        r = unit_name_mangle(name, UNIT_NAME_NOGLOB, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         /* We don't use unit_dbus_path_from_name() directly since we
          * don't want to load the unit if it isn't loaded. */
@@ -2440,9 +2451,9 @@ static int check_triggering_units(
         char **i;
         int r;
 
-        n = unit_name_mangle(name, MANGLE_NOGLOB);
-        if (!n)
-                return log_oom();
+        r = unit_name_mangle(name, UNIT_NAME_NOGLOB, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         path = unit_dbus_path_from_name(n);
         if (!path)
@@ -2596,17 +2607,17 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
 
         _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
         char **name;
-        int r = 0, i;
+        int r, i;
 
         STRV_FOREACH(name, names) {
                 char *t;
 
                 if (suffix)
-                        t = unit_name_mangle_with_suffix(*name, MANGLE_GLOB, suffix);
+                        r = unit_name_mangle_with_suffix(*name, UNIT_NAME_GLOB, suffix, &t);
                 else
-                        t = unit_name_mangle(*name, MANGLE_GLOB);
-                if (!t)
-                        return log_oom();
+                        r = unit_name_mangle(*name, UNIT_NAME_GLOB, &t);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle name: %m");
 
                 if (string_is_glob(t))
                         r = strv_consume(&globs, t);
@@ -2785,6 +2796,33 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
                 return -EINVAL;
         }
 
+        if (!strv_isempty(arg_wall)) {
+                _cleanup_free_ char *m;
+
+                m = strv_join(arg_wall, " ");
+                if (!m)
+                        return log_oom();
+
+                r = sd_bus_call_method(
+                               bus,
+                               "org.freedesktop.login1",
+                               "/org/freedesktop/login1",
+                               "org.freedesktop.login1.Manager",
+                               "SetWallMessage",
+                               &error,
+                               NULL,
+                               "sb",
+                               m,
+                               !arg_no_wall);
+
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to set wall message, ignoring: %s",
+                                          bus_error_message(&error, r));
+                        sd_bus_error_free(&error);
+                }
+        }
+
+
         r = sd_bus_call_method(
                         bus,
                         "org.freedesktop.login1",
@@ -3318,8 +3356,7 @@ static void print_status_info(
                         if (! dir || last) {
                                 printf(dir ? "        " : "  Drop-In: ");
 
-                                free(dir);
-                                dir = NULL;
+                                dir = mfree(dir);
 
                                 if (path_get_parent(*dropin, &dir) < 0) {
                                         log_oom();
@@ -3522,7 +3559,7 @@ static void print_status_info(
 
         if (i->control_group &&
             (i->main_pid > 0 || i->control_pid > 0 ||
-             ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0))) {
+             ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
                 unsigned c;
 
                 printf("   CGroup: %s\n", i->control_group);
@@ -3548,7 +3585,7 @@ static void print_status_info(
                 }
         }
 
-        if (i->id && arg_transport == BUS_TRANSPORT_LOCAL) {
+        if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
                 show_journal_by_unit(
                                 stdout,
                                 i->id,
@@ -3561,7 +3598,6 @@ static void print_status_info(
                                 SD_JOURNAL_LOCAL_ONLY,
                                 arg_scope == UNIT_FILE_SYSTEM,
                                 ellipsized);
-        }
 
         if (i->need_daemon_reload)
                 warn_unit_file_changed(i->id);
@@ -4232,10 +4268,8 @@ static int show_one(
                         &error,
                         &reply,
                         "s", "");
-        if (r < 0) {
-                log_error("Failed to get properties: %s", bus_error_message(&error, r));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
 
         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
         if (r < 0)
@@ -4399,7 +4433,7 @@ static int show_all(
 static int show_system_status(sd_bus *bus) {
         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
         _cleanup_free_ char *hn = NULL;
-        struct machine_info mi = {};
+        _cleanup_(machine_info_clear) struct machine_info mi = {};
         const char *on, *off;
         int r;
 
@@ -4446,9 +4480,6 @@ static int show_system_status(sd_bus *bus) {
                 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags());
         }
 
-        free(mi.state);
-        free(mi.control_group);
-
         return 0;
 }
 
@@ -4674,9 +4705,9 @@ static int set_property(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        n = unit_name_mangle(args[1], MANGLE_NOGLOB);
-        if (!n)
-                return log_oom();
+        r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &n);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         r = sd_bus_message_append(m, "sb", n, arg_runtime);
         if (r < 0)
@@ -4722,12 +4753,15 @@ static int snapshot(sd_bus *bus, char **args) {
 
         polkit_agent_open_if_enabled();
 
-        if (strv_length(args) > 1)
-                n = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".snapshot");
-        else
+        if (strv_length(args) > 1) {
+                r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate unit name: %m");
+        } else {
                 n = strdup("");
-        if (!n)
-                return log_oom();
+                if (!n)
+                        return log_oom();
+        }
 
         r = sd_bus_call_method(
                         bus,
@@ -5093,7 +5127,7 @@ static int import_environment(sd_bus *bus, char **args) {
 static int enable_sysv_units(const char *verb, char **args) {
         int r = 0;
 
-#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
+#if defined(HAVE_SYSV_COMPAT)
         unsigned f = 0;
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
@@ -5108,7 +5142,7 @@ static int enable_sysv_units(const char *verb, char **args) {
         /* Processes all SysV units, and reshuffles the array so that
          * afterwards only the native units remain */
 
-        r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, arg_root, NULL, NULL, NULL);
+        r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, arg_root, NULL, NULL, NULL);
         if (r < 0)
                 return r;
 
@@ -5118,7 +5152,7 @@ static int enable_sysv_units(const char *verb, char **args) {
                 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
                 bool found_native = false, found_sysv;
                 unsigned c = 1;
-                const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
+                const char *argv[6] = { ROOTLIBEXECDIR "/systemd-sysv-install", NULL, NULL, NULL, NULL };
                 char **k;
                 int j;
                 pid_t pid;
@@ -5144,7 +5178,10 @@ static int enable_sysv_units(const char *verb, char **args) {
                                 break;
                 }
 
-                if (found_native)
+                /* If we have both a native unit and a SysV script,
+                 * enable/disable them both (below); for is-enabled, prefer the
+                 * native unit */
+                if (found_native && streq(verb, "is-enabled"))
                         continue;
 
                 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
@@ -5156,15 +5193,16 @@ static int enable_sysv_units(const char *verb, char **args) {
                 if (!found_sysv)
                         continue;
 
-                log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
+                if (found_native)
+                        log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]);
+                else
+                        log_info("%s is not a native service, redirecting to systemd-sysv-install", name);
 
                 if (!isempty(arg_root))
                         argv[c++] = q = strappend("--root=", arg_root);
 
+                argv[c++] = verb;
                 argv[c++] = basename(p);
-                argv[c++] =
-                        streq(verb, "enable") ? "on" :
-                        streq(verb, "disable") ? "off" : "--level=5";
                 argv[c] = NULL;
 
                 l = strv_join((char**)argv, " ");
@@ -5179,7 +5217,11 @@ static int enable_sysv_units(const char *verb, char **args) {
                 else if (pid == 0) {
                         /* Child */
 
+                        (void) reset_all_signal_handlers();
+                        (void) reset_signal_mask();
+
                         execv(argv[0], (char**) argv);
+                        log_error("Failed to execute %s: %m", argv[0]);
                         _exit(EXIT_FAILURE);
                 }
 
@@ -5205,6 +5247,9 @@ static int enable_sysv_units(const char *verb, char **args) {
                 } else
                         return -EPROTO;
 
+                if (found_native)
+                        continue;
+
                 /* Remove this entry, so that we don't try enabling it as native unit */
                 assert(f > 0);
                 f--;
@@ -5218,25 +5263,29 @@ static int enable_sysv_units(const char *verb, char **args) {
 
 static int mangle_names(char **original_names, char ***mangled_names) {
         char **i, **l, **name;
+        int r;
 
-        l = new(char*, strv_length(original_names) + 1);
+        l = i = new(char*, strv_length(original_names) + 1);
         if (!l)
                 return log_oom();
 
-        i = l;
         STRV_FOREACH(name, original_names) {
 
                 /* When enabling units qualified path names are OK,
                  * too, hence allow them explicitly. */
 
-                if (is_path(*name))
+                if (is_path(*name)) {
                         *i = strdup(*name);
-                else
-                        *i = unit_name_mangle(*name, MANGLE_NOGLOB);
-
-                if (!*i) {
-                        strv_free(l);
-                        return log_oom();
+                        if (!*i) {
+                                strv_free(l);
+                                return log_oom();
+                        }
+                } else {
+                        r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
+                        if (r < 0) {
+                                strv_free(l);
+                                return log_error_errno(r, "Failed to mangle unit name: %m");
+                        }
                 }
 
                 i++;
@@ -5381,7 +5430,7 @@ static int enable_unit(sd_bus *bus, char **args) {
                                 return bus_log_parse_error(r);
                 }
 
-                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
                 if (r < 0)
                         return r;
 
@@ -5403,6 +5452,18 @@ static int enable_unit(sd_bus *bus, char **args) {
                             "3) A unit may be started when needed via activation (socket, path, timer,\n"
                             "   D-Bus, udev, scripted systemctl call, ...).\n");
 
+        if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) {
+                char *new_args[n_changes + 2];
+                unsigned i;
+
+                new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
+                for (i = 0; i < n_changes; i++)
+                        new_args[i + 1] = basename(changes[i].path);
+                new_args[i + 1] = NULL;
+
+                r = start_unit(bus, new_args);
+        }
+
 finish:
         unit_file_changes_free(changes, n_changes);
 
@@ -5419,9 +5480,9 @@ static int add_dependency(sd_bus *bus, char **args) {
         if (!args[1])
                 return 0;
 
-        target = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
-        if (!target)
-                return log_oom();
+        r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mangle unit name: %m");
 
         r = mangle_names(args+2, &names);
         if (r < 0)
@@ -5478,7 +5539,7 @@ static int add_dependency(sd_bus *bus, char **args) {
                         return r;
                 }
 
-                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
                 if (r < 0)
                         return r;
 
@@ -5532,7 +5593,7 @@ static int preset_all(sd_bus *bus, char **args) {
                         return r;
                 }
 
-                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+                r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
                 if (r < 0)
                         return r;
 
@@ -5651,7 +5712,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
         assert(original_path);
         assert(ret_tmp_fn);
 
-        r = tempfn_random(new_path, &t);
+        r = tempfn_random(new_path, NULL, &t);
         if (r < 0)
                 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
 
@@ -5715,10 +5776,10 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
 
         if (arg_runtime) {
                 if (access(path, F_OK) >= 0)
-                        return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overriden by \"%s\" anyway.",
+                        return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
                                                run, path);
                 if (path2 && access(path2, F_OK) >= 0)
-                        return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overriden by \"%s\" anyway.",
+                        return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
                                                run, path2);
                 *ret_path = run;
                 run = NULL;
@@ -5819,20 +5880,15 @@ static int run_editor(char **paths) {
 
         if (pid == 0) {
                 const char **args;
-                char *editor;
+                char *editor, **editor_args = NULL;
                 char **tmp_path, **original_path, *p;
-                unsigned i = 1;
+                unsigned n_editor_args = 0, i = 1;
                 size_t argc;
 
-                argc = strv_length(paths)/2 + 1;
-                args = newa(const char*, argc + 1);
+                (void) reset_all_signal_handlers();
+                (void) reset_signal_mask();
 
-                args[0] = NULL;
-                STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
-                        args[i] = *tmp_path;
-                        i++;
-                }
-                args[argc] = NULL;
+                argc = strv_length(paths)/2 + 1;
 
                 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
                  * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
@@ -5845,11 +5901,32 @@ static int run_editor(char **paths) {
                         editor = getenv("VISUAL");
 
                 if (!isempty(editor)) {
-                        args[0] = editor;
-                        execvp(editor, (char* const*) args);
+                        editor_args = strv_split(editor, WHITESPACE);
+                        if (!editor_args) {
+                                (void) log_oom();
+                                _exit(EXIT_FAILURE);
+                        }
+                        n_editor_args = strv_length(editor_args);
+                        argc += n_editor_args - 1;
+                }
+                args = newa(const char*, argc + 1);
+
+                if (n_editor_args > 0) {
+                        args[0] = editor_args[0];
+                        for (; i < n_editor_args; i++)
+                                args[i] = editor_args[i];
                 }
 
-                FOREACH_STRING(p, "nano", "vim", "vi") {
+                STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
+                        args[i] = *tmp_path;
+                        i++;
+                }
+                args[i] = NULL;
+
+                if (n_editor_args > 0)
+                        execvp(args[0], (char* const*) args);
+
+                FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
                         args[0] = p;
                         execvp(p, (char* const*) args);
                         /* We do not fail if the editor doesn't exist
@@ -6008,6 +6085,7 @@ static void systemctl_help(void) {
                "                      When shutting down or sleeping, ignore inhibitors\n"
                "     --kill-who=WHO   Who to send signal to\n"
                "  -s --signal=SIGNAL  Which signal to send\n"
+               "     --now            Start or stop unit in addition to enabling or disabling it\n"
                "  -q --quiet          Suppress output\n"
                "     --no-block       Do not wait until operation finished\n"
                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
@@ -6207,6 +6285,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_JOB_MODE,
                 ARG_PRESET_MODE,
                 ARG_FIRMWARE_SETUP,
+                ARG_NOW,
+                ARG_MESSAGE,
         };
 
         static const struct option options[] = {
@@ -6250,6 +6330,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "recursive",           no_argument,       NULL, 'r'                     },
                 { "preset-mode",         required_argument, NULL, ARG_PRESET_MODE         },
                 { "firmware-setup",      no_argument,       NULL, ARG_FIRMWARE_SETUP      },
+                { "now",                 no_argument,       NULL, ARG_NOW                 },
+                { "message",             required_argument, NULL, ARG_MESSAGE             },
                 {}
         };
 
@@ -6530,6 +6612,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_NOW:
+                        arg_now = true;
+                        break;
+
+                case ARG_MESSAGE:
+                        if (strv_extend(&arg_wall, optarg) < 0)
+                                return log_oom();
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -7173,51 +7264,6 @@ found:
         return verb->dispatch(bus, argv + optind);
 }
 
-static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
-
-        struct sd_shutdown_command c = {
-                .usec = t,
-                .mode = mode,
-                .dry_run = dry_run,
-                .warn_wall = warn,
-        };
-
-        union sockaddr_union sockaddr = {
-                .un.sun_family = AF_UNIX,
-                .un.sun_path = "/run/systemd/shutdownd",
-        };
-
-        struct iovec iovec[2] = {{
-                 .iov_base = (char*) &c,
-                 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
-        }};
-
-        struct msghdr msghdr = {
-                .msg_name = &sockaddr,
-                .msg_namelen = offsetof(struct sockaddr_un, sun_path)
-                               + strlen("/run/systemd/shutdownd"),
-                .msg_iov = iovec,
-                .msg_iovlen = 1,
-        };
-
-        _cleanup_close_ int fd;
-
-        fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
-        if (fd < 0)
-                return -errno;
-
-        if (!isempty(message)) {
-                iovec[1].iov_base = (char*) message;
-                iovec[1].iov_len = strlen(message);
-                msghdr.msg_iovlen++;
-        }
-
-        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
-                return -errno;
-
-        return 0;
-}
-
 static int reload_with_fallback(sd_bus *bus) {
 
         if (bus) {
@@ -7279,6 +7325,7 @@ static int halt_now(enum action a) {
                 reboot(RB_POWER_OFF);
                 return -errno;
 
+        case ACTION_KEXEC:
         case ACTION_REBOOT: {
                 _cleanup_free_ char *param = NULL;
 
@@ -7325,23 +7372,58 @@ static int halt_main(sd_bus *bus) {
         }
 
         if (arg_when > 0) {
-                _cleanup_free_ char *m;
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
+                _cleanup_free_ char *m = NULL;
+
+                if (avoid_bus()) {
+                        log_error("Unable to perform operation without bus connection.");
+                        return -ENOSYS;
+                }
+
+                r = sd_bus_open_system(&b);
+                if (r < 0)
+                        return log_error_errno(r, "Unable to open system bus: %m");
 
                 m = strv_join(arg_wall, " ");
                 if (!m)
                         return log_oom();
 
-                r = send_shutdownd(arg_when,
-                                   arg_action == ACTION_HALT     ? 'H' :
-                                   arg_action == ACTION_POWEROFF ? 'P' :
-                                   arg_action == ACTION_KEXEC    ? 'K' :
-                                                                   'r',
-                                   arg_dry,
-                                   !arg_no_wall,
-                                   m);
+                r = sd_bus_call_method(
+                               b,
+                               "org.freedesktop.login1",
+                               "/org/freedesktop/login1",
+                               "org.freedesktop.login1.Manager",
+                               "SetWallMessage",
+                               &error,
+                               NULL,
+                               "sb",
+                               m,
+                               !arg_no_wall);
 
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to set wall message, ignoring: %s",
+                                          bus_error_message(&error, r));
+                        sd_bus_error_free(&error);
+                }
+
+                r = sd_bus_call_method(
+                                b,
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                "ScheduleShutdown",
+                                &error,
+                                NULL,
+                                "st",
+                                arg_action == ACTION_HALT     ? "halt" :
+                                arg_action == ACTION_POWEROFF ? "poweroff" :
+                                arg_action == ACTION_KEXEC    ? "kexec" :
+                                                                "reboot",
+                                arg_when);
                 if (r < 0)
-                        log_warning_errno(r, "Failed to talk to shutdownd, proceeding with immediate shutdown: %m");
+                        log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
+                                          bus_error_message(&error, r));
                 else {
                         char date[FORMAT_TIMESTAMP_MAX];
 
@@ -7390,7 +7472,7 @@ static int runlevel_main(void) {
 }
 
 int main(int argc, char*argv[]) {
-        _cleanup_bus_close_unref_ sd_bus *bus = NULL;
+        _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
         int r;
 
         setlocale(LC_ALL, "");
@@ -7457,8 +7539,19 @@ int main(int argc, char*argv[]) {
                 break;
 
         case ACTION_CANCEL_SHUTDOWN: {
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
                 _cleanup_free_ char *m = NULL;
 
+                if (avoid_bus()) {
+                        log_error("Unable to perform operation without bus connection.");
+                        return -ENOSYS;
+                }
+
+                r = sd_bus_open_system(&b);
+                if (r < 0)
+                        return log_error_errno(r, "Unable to open system bus: %m");
+
                 if (arg_wall) {
                         m = strv_join(arg_wall, " ");
                         if (!m) {
@@ -7467,9 +7560,35 @@ int main(int argc, char*argv[]) {
                         }
                 }
 
-                r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
+                r = sd_bus_call_method(
+                               b,
+                               "org.freedesktop.login1",
+                               "/org/freedesktop/login1",
+                               "org.freedesktop.login1.Manager",
+                               "SetWallMessage",
+                               &error,
+                               NULL,
+                               "sb",
+                               m,
+                               !arg_no_wall);
+
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to set wall message, ignoring: %s",
+                                          bus_error_message(&error, r));
+                        sd_bus_error_free(&error);
+                }
+
+                r = sd_bus_call_method(
+                                b,
+                                "org.freedesktop.login1",
+                                "/org/freedesktop/login1",
+                                "org.freedesktop.login1.Manager",
+                                "CancelScheduledShutdown",
+                                &error,
+                                NULL, NULL);
                 if (r < 0)
-                        log_warning_errno(r, "Failed to talk to shutdownd, shutdown hasn't been cancelled: %m");
+                        log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s",
+                                          bus_error_message(&error, r));
                 break;
         }