chiark / gitweb /
missing: remove fanotify
[elogind.git] / src / systemctl / systemctl.c
index daf7e31de9cf13c99794ec9c1965bf29921a919e..28eaa6a8475ebebcadf27c27f5ec7c4ac08e0490 100644 (file)
@@ -137,23 +137,6 @@ static unsigned arg_lines = 10;
 static OutputMode arg_output = OUTPUT_SHORT;
 static bool arg_plain = false;
 
-static const struct {
-        const char *verb;
-        const char *method;
-} unit_actions[] = {
-        { "start",                 "StartUnit" },
-        { "stop",                  "StopUnit" },
-        { "condstop",              "StopUnit" },
-        { "reload",                "ReloadUnit" },
-        { "restart",               "RestartUnit" },
-        { "try-restart",           "TryRestartUnit" },
-        { "condrestart",           "TryRestartUnit" },
-        { "reload-or-restart",     "ReloadOrRestartUnit" },
-        { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
-        { "condreload",            "ReloadOrTryRestartUnit" },
-        { "force-reload",          "ReloadOrTryRestartUnit" }
-};
-
 static bool original_stdout_is_tty;
 
 static int daemon_reload(sd_bus *bus, char **args);
@@ -594,7 +577,7 @@ static int get_unit_list_recursive(
         assert(_unit_infos);
         assert(_machines);
 
-        replies = set_new(NULL, NULL);
+        replies = set_new(NULL);
         if (!replies)
                 return log_oom();
 
@@ -617,7 +600,7 @@ static int get_unit_list_recursive(
                         return r;
 
                 STRV_FOREACH(i, machines) {
-                        _cleanup_bus_unref_ sd_bus *container = NULL;
+                        _cleanup_bus_close_unref_ sd_bus *container = NULL;
                         int k;
 
                         r = sd_bus_open_system_container(&container, *i);
@@ -1338,7 +1321,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
                 Iterator i;
                 unsigned n_units;
 
-                h = hashmap_new(string_hash_func, string_compare_func);
+                h = hashmap_new(&string_hash_ops);
                 if (!h)
                         return log_oom();
 
@@ -1350,8 +1333,9 @@ static int list_unit_files(sd_bus *bus, char **args) {
                 }
 
                 n_units = hashmap_size(h);
+
                 units = new(UnitFileList, n_units);
-                if (!units) {
+                if (!units && n_units > 0) {
                         unit_file_list_free(h);
                         return log_oom();
                 }
@@ -1407,14 +1391,13 @@ static int list_unit_files(sd_bus *bus, char **args) {
                         return bus_log_parse_error(r);
         }
 
-        if (c > 0) {
-                qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
-                output_unit_file_list(units, c);
-        }
+        qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
+        output_unit_file_list(units, c);
 
-        if (avoid_bus())
+        if (avoid_bus()) {
                 for (unit = units; unit < units + c; unit++)
                         free(unit->path);
+        }
 
         return 0;
 }
@@ -1688,7 +1671,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_unref_ sd_bus *container = NULL;
+        _cleanup_bus_close_unref_ sd_bus *container = NULL;
         int r;
 
         assert(mi);
@@ -1982,18 +1965,28 @@ static int set_default(sd_bus *bus, char **args) {
 
                 r = 0;
         } else {
-                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                r = sd_bus_call_method(
+                r = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "SetDefaultTarget",
-                                &error,
-                                &reply,
-                                "sb", unit, true);
+                                "SetDefaultTarget");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append(m, "sb", unit, 1);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
                 if (r < 0) {
                         log_error("Failed to set default target: %s", bus_error_message(&error, -r));
                         return r;
@@ -2160,6 +2153,7 @@ static int list_jobs(sd_bus *bus, char **args) {
 static int cancel_job(sd_bus *bus, char **args) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         char **name;
+        int r = 0;
 
         assert(args);
 
@@ -2167,31 +2161,43 @@ static int cancel_job(sd_bus *bus, char **args) {
                 return daemon_reload(bus, args);
 
         STRV_FOREACH(name, args+1) {
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
                 uint32_t id;
-                int r;
+                int q;
 
-                r = safe_atou32(*name, &id);
-                if (r < 0) {
-                        log_error("Failed to parse job id \"%s\": %s", *name, strerror(-r));
-                        return r;
+                q = safe_atou32(*name, &id);
+                if (q < 0) {
+                        log_error("Failed to parse job id \"%s\": %s", *name, strerror(-q));
+                        return q;
                 }
 
-                r = sd_bus_call_method(
+                q = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "CancelJob",
-                                &error,
-                                NULL,
-                                "u", id);
-                if (r < 0) {
-                        log_error("Failed to cancel job %u: %s", (unsigned) id, bus_error_message(&error, r));
-                        return r;
+                                "CancelJob");
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+                if (q < 0)
+                        return bus_log_create_error(1);
+
+                q = sd_bus_message_append(m, "u", id);
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_call(bus, m, 0, &error, NULL);
+                if (q < 0) {
+                        log_error("Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
+                        if (r == 0)
+                                r = q;
                 }
         }
 
-        return 0;
+        return r;
 }
 
 static int need_daemon_reload(sd_bus *bus, const char *unit) {
@@ -2350,9 +2356,19 @@ static int check_wait_response(WaitData *d) {
                 else if (streq(d->result, "canceled"))
                         log_error("Job for %s canceled.", strna(d->name));
                 else if (streq(d->result, "dependency"))
-                        log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d->name));
-                else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
-                        log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d->name), strna(d->name));
+                        log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
+                else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
+                        if (d->name) {
+                                bool quotes;
+
+                                quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
+
+                                log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
+                                          d->name,
+                                          quotes ? "'" : "", d->name, quotes ? "'" : "");
+                        } else
+                                log_error("Job failed. See \"journalctl -xe\" for details.");
+                }
         }
 
         if (streq(d->result, "timeout"))
@@ -2382,7 +2398,7 @@ static int wait_for_jobs(sd_bus *bus, Set *s) {
         while (!set_isempty(s)) {
                 q = bus_process_wait(bus);
                 if (q < 0) {
-                        log_error("Failed to wait for response: %s", strerror(-r));
+                        log_error("Failed to wait for response: %s", strerror(-q));
                         return q;
                 }
 
@@ -2529,6 +2545,23 @@ static int check_triggering_units(
         return 0;
 }
 
+static const struct {
+        const char *verb;
+        const char *method;
+} unit_actions[] = {
+        { "start",                 "StartUnit" },
+        { "stop",                  "StopUnit" },
+        { "condstop",              "StopUnit" },
+        { "reload",                "ReloadUnit" },
+        { "restart",               "RestartUnit" },
+        { "try-restart",           "TryRestartUnit" },
+        { "condrestart",           "TryRestartUnit" },
+        { "reload-or-restart",     "ReloadOrRestartUnit" },
+        { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
+        { "condreload",            "ReloadOrTryRestartUnit" },
+        { "force-reload",          "ReloadOrTryRestartUnit" }
+};
+
 static const char *verb_to_method(const char *verb) {
        uint i;
 
@@ -2557,7 +2590,7 @@ static int start_unit_one(
                 sd_bus_error *error,
                 Set *s) {
 
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
         const char *path;
         int r;
 
@@ -2567,15 +2600,26 @@ static int start_unit_one(
         assert(error);
 
         log_debug("Calling manager for %s on %s, %s", method, name, mode);
-        r = sd_bus_call_method(
+
+        r = sd_bus_message_new_method_call(
                         bus,
+                        &m,
                         "org.freedesktop.systemd1",
                         "/org/freedesktop/systemd1",
                         "org.freedesktop.systemd1.Manager",
-                        method,
-                        error,
-                        &reply,
-                        "ss", name, mode);
+                        method);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(m, "ss", name, mode);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, error, &reply);
         if (r < 0) {
                 const char *verb;
 
@@ -2694,7 +2738,7 @@ static enum action verb_to_action(const char *verb) {
 static int start_unit(sd_bus *bus, char **args) {
         _cleanup_set_free_free_ Set *s = NULL;
         _cleanup_strv_free_ char **names = NULL;
-        const char *method, *mode, *one_name;
+        const char *method, *mode, *one_name, *suffix = NULL;
         char **name;
         int r = 0;
 
@@ -2707,8 +2751,11 @@ static int start_unit(sd_bus *bus, char **args) {
                 method = verb_to_method(args[0]);
                 action = verb_to_action(args[0]);
 
-                mode = streq(args[0], "isolate") ? "isolate" :
-                       action_table[action].mode ?: arg_job_mode;
+                if (streq(args[0], "isolate")) {
+                        mode = "isolate";
+                        suffix = ".target";
+                } else
+                        mode = action_table[action].mode ?: arg_job_mode;
 
                 one_name = action_table[action].target;
         } else {
@@ -2724,7 +2771,7 @@ static int start_unit(sd_bus *bus, char **args) {
         if (one_name)
                 names = strv_new(one_name, NULL);
         else {
-                r = expand_names(bus, args + 1, NULL, &names);
+                r = expand_names(bus, args + 1, suffix, &names);
                 if (r < 0)
                         log_error("Failed to expand names: %s", strerror(-r));
         }
@@ -2736,7 +2783,7 @@ static int start_unit(sd_bus *bus, char **args) {
                         return r;
                 }
 
-                s = set_new(string_hash_func, string_compare_func);
+                s = set_new(&string_hash_ops);
                 if (!s)
                         return log_oom();
         }
@@ -2814,7 +2861,7 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
                         method,
                         &error,
                         NULL,
-                        "b", true);
+                        "b", arg_ask_password);
         if (r < 0)
                 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
 
@@ -3037,18 +3084,29 @@ static int kill_unit(sd_bus *bus, char **args) {
                 log_error("Failed to expand names: %s", strerror(-r));
 
         STRV_FOREACH(name, names) {
-                q = sd_bus_call_method(
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+
+                q = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "KillUnit",
-                                &error,
-                                NULL,
-                                "ssi", *names, arg_kill_who, arg_signal);
+                                "KillUnit");
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_message_append(m, "ssi", *names, arg_kill_who, arg_signal);
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_call(bus, m, 0, &error, NULL);
                 if (q < 0) {
-                        log_error("Failed to kill unit %s: %s",
-                                  *names, bus_error_message(&error, r));
+                        log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
                         if (r == 0)
                                 r = q;
                 }
@@ -3399,7 +3457,7 @@ static void print_status_info(
 
         if (i->main_pid > 0 || i->control_pid > 0) {
                 if (i->main_pid > 0) {
-                        printf(" Main PID: %u", (unsigned) i->main_pid);
+                        printf(" Main PID: "PID_FMT, i->main_pid);
 
                         if (i->running) {
                                 _cleanup_free_ char *comm = NULL;
@@ -3430,7 +3488,7 @@ static void print_status_info(
                 if (i->control_pid > 0) {
                         _cleanup_free_ char *c = NULL;
 
-                        printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid);
+                        printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid);
 
                         get_process_comm(i->control_pid, &c);
                         if (c)
@@ -3818,7 +3876,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         if (u > 0)
-                                printf("%s=%u\n", name, (unsigned) u);
+                                printf("%s=%"PRIu32"\n", name, u);
                         else if (arg_all)
                                 printf("%s=\n", name);
 
@@ -3989,14 +4047,14 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
 
                                 tt = strv_join(info.argv, " ");
 
-                                printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
+                                printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }\n",
                                        name,
                                        strna(info.path),
                                        strna(tt),
                                        yes_no(info.ignore),
                                        strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
                                        strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
-                                       (unsigned) info. pid,
+                                       info.pid,
                                        sigchld_code_to_string(info.code),
                                        info.status,
                                        info.code == CLD_EXITED ? "" : "/",
@@ -4439,7 +4497,6 @@ static int show(sd_bus *bus, char **args) {
 }
 
 static int cat(sd_bus *bus, char **args) {
-        _cleanup_free_ char *unit = NULL;
         _cleanup_strv_free_ char **names = NULL;
         char **name;
         bool first = true;
@@ -4457,7 +4514,7 @@ static int cat(sd_bus *bus, char **args) {
         STRV_FOREACH(name, names) {
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_strv_free_ char **dropin_paths = NULL;
-                _cleanup_free_ char *fragment_path = NULL;
+                _cleanup_free_ char *fragment_path = NULL, *unit = NULL;
                 char **path;
 
                 unit = unit_dbus_path_from_name(*name);
@@ -4549,6 +4606,10 @@ static int set_property(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+        if (r < 0)
+                return bus_log_create_error(r);
+
         n = unit_name_mangle(args[1], MANGLE_NOGLOB);
         if (!n)
                 return log_oom();
@@ -4590,7 +4651,7 @@ static int set_property(sd_bus *bus, char **args) {
 
 static int snapshot(sd_bus *bus, char **args) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
         _cleanup_free_ char *n = NULL, *id = NULL;
         const char *path;
         int r;
@@ -4602,15 +4663,25 @@ static int snapshot(sd_bus *bus, char **args) {
         if (!n)
                 return log_oom();
 
-        r = sd_bus_call_method(
+        r = sd_bus_message_new_method_call(
                         bus,
+                        &m,
                         "org.freedesktop.systemd1",
                         "/org/freedesktop/systemd1",
                         "org.freedesktop.systemd1.Manager",
-                        "CreateSnapshot",
-                        &error,
-                        &reply,
-                        "sb", n, false);
+                        "CreateSnapshot");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(m, "sb", n, false);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, &error, &reply);
         if (r < 0) {
                 log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
                 return r;
@@ -4643,7 +4714,7 @@ static int delete_snapshot(sd_bus *bus, char **args) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_strv_free_ char **names = NULL;
         char **name;
-        int r, q;
+        int r;
 
         assert(args);
 
@@ -4652,18 +4723,30 @@ static int delete_snapshot(sd_bus *bus, char **args) {
                 log_error("Failed to expand names: %s", strerror(-r));
 
         STRV_FOREACH(name, names) {
-                q = sd_bus_call_method(
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+                int q;
+
+                q = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "RemoveSnapshot",
-                                &error,
-                                NULL,
-                                "s", *name);
+                                "RemoveSnapshot");
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_message_append(m, "s", *name);
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_call(bus, m, 0, &error, NULL);
                 if (q < 0) {
-                        log_error("Failed to remove snapshot %s: %s",
-                                  *name, bus_error_message(&error, r));
+                        log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
                         if (r == 0)
                                 r = q;
                 }
@@ -4674,6 +4757,7 @@ static int delete_snapshot(sd_bus *bus, char **args) {
 
 static int daemon_reload(sd_bus *bus, char **args) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         const char *method;
         int r;
 
@@ -4697,16 +4781,21 @@ static int daemon_reload(sd_bus *bus, char **args) {
                                     /* "daemon-reload" */ "Reload";
         }
 
-        r = sd_bus_call_method(
+        r = sd_bus_message_new_method_call(
                         bus,
+                        &m,
                         "org.freedesktop.systemd1",
                         "/org/freedesktop/systemd1",
                         "org.freedesktop.systemd1.Manager",
-                        method,
-                        &error,
-                        NULL,
-                        NULL);
+                        method);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+        if (r < 0)
+                return bus_log_create_error(r);
 
+        r = sd_bus_call(bus, m, 0, &error, NULL);
         if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
                 /* There's always a fallback possible for
                  * legacy actions. */
@@ -4735,18 +4824,29 @@ static int reset_failed(sd_bus *bus, char **args) {
                 log_error("Failed to expand names: %s", strerror(-r));
 
         STRV_FOREACH(name, names) {
-                q = sd_bus_call_method(
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+
+                q = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "ResetFailedUnit",
-                                &error,
-                                NULL,
-                                "s", *name);
+                                "ResetFailedUnit");
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_message_append(m, "s", *name);
+                if (q < 0)
+                        return bus_log_create_error(q);
+
+                q = sd_bus_call(bus, m, 0, &error, NULL);
                 if (q < 0) {
-                        log_error("Failed to reset failed state of unit %s: %s",
-                                  *name, bus_error_message(&error, r));
+                        log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
                         if (r == 0)
                                 r = q;
                 }
@@ -4827,7 +4927,7 @@ static int switch_root(sd_bus *bus, char **args) {
                 const char *root_systemd_path = NULL, *root_init_path = NULL;
 
                 root_systemd_path = strappenda(root, "/" SYSTEMD_BINARY_PATH);
-                root_init_path = strappenda3(root, "/", init);
+                root_init_path = strappenda(root, "/", init);
 
                 /* If the passed init is actually the same as the
                  * systemd binary, then let's suppress it. */
@@ -4877,6 +4977,10 @@ static int set_environment(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+        if (r < 0)
+                return bus_log_create_error(r);
+
         r = sd_bus_message_append_strv(m, args + 1);
         if (r < 0)
                 return bus_log_create_error(r);
@@ -4908,6 +5012,10 @@ static int import_environment(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+        if (r < 0)
+                return bus_log_create_error(r);
+
         if (strv_isempty(args + 1))
                 r = sd_bus_message_append_strv(m, environ);
         else {
@@ -5219,6 +5327,10 @@ static int enable_unit(sd_bus *bus, char **args) {
                 if (r < 0)
                         return bus_log_create_error(r);
 
+                r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
                 r = sd_bus_message_append_strv(m, names);
                 if (r < 0)
                         return bus_log_create_error(r);
@@ -5279,6 +5391,92 @@ finish:
         return r;
 }
 
+static int add_dependency(sd_bus *bus, char **args) {
+        _cleanup_strv_free_ char **names = NULL;
+        _cleanup_free_ char *target = NULL;
+        const char *verb = args[0];
+        UnitDependency dep;
+        int r = 0;
+
+        if (!args[1])
+                return 0;
+
+        target = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
+        if (!target)
+                return log_oom();
+
+        r = mangle_names(args+2, &names);
+        if (r < 0)
+                return r;
+
+        if (streq(verb, "add-wants"))
+                dep = UNIT_WANTS;
+        else if (streq(verb, "add-requires"))
+                dep = UNIT_REQUIRES;
+        else
+                assert_not_reached("Unknown verb");
+
+        if (!bus || avoid_bus()) {
+                UnitFileChange *changes = NULL;
+                unsigned n_changes = 0;
+
+                r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
+
+                if (r < 0) {
+                        log_error("Can't add dependency: %s", strerror(-r));
+                        return r;
+                }
+
+                if (!arg_quiet)
+                        dump_unit_file_changes(changes, n_changes);
+
+                unit_file_changes_free(changes, n_changes);
+
+        } else {
+                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
+                r = sd_bus_message_new_method_call(
+                                bus,
+                                &m,
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager",
+                                "AddDependencyUnitFiles");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append_strv(m, names);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
+                if (r < 0) {
+                        log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+                        return r;
+                }
+
+                r = deserialize_and_dump_unit_file_changes(reply);
+                if (r < 0)
+                        return r;
+
+                if (!arg_no_reload)
+                        r = daemon_reload(bus, args);
+                else
+                        r = 0;
+        }
+
+        return r;
+}
+
 static int preset_all(sd_bus *bus, char **args) {
         UnitFileChange *changes = NULL;
         unsigned n_changes = 0;
@@ -5298,21 +5496,33 @@ static int preset_all(sd_bus *bus, char **args) {
                 r = 0;
 
         } else {
-                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+                _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                r = sd_bus_call_method(
+                r = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "PresetAllUnitFiles",
-                                &error,
-                                &reply,
+                                "PresetAllUnitFiles");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append(
+                                m,
                                 "sbb",
                                 unit_file_preset_mode_to_string(arg_preset_mode),
                                 arg_runtime,
                                 arg_force);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
                 if (r < 0) {
                         log_error("Failed to execute operation: %s", bus_error_message(&error, r));
                         return r;
@@ -5524,6 +5734,10 @@ static void systemctl_help(void) {
                "  unmask NAME...                  Unmask one or more units\n"
                "  link PATH...                    Link one or more units files into\n"
                "                                  the search path\n"
+               "  add-wants TARGET NAME...        Add 'Wants' dependency for the target\n"
+               "                                  on specified one or more units\n"
+               "  add-requires TARGET NAME...     Add 'Requires' dependency for the target\n"
+               "                                  on specified one or more units\n"
                "  get-default                     Get the name of the default target\n"
                "  set-default NAME                Set the default target\n\n"
                "Machine Commands:\n"
@@ -6534,6 +6748,8 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
                 { "get-default",           EQUAL, 1, get_default,      NOBUS },
                 { "set-property",          MORE,  3, set_property      },
                 { "is-system-running",     EQUAL, 1, is_system_running },
+                { "add-wants",             MORE,  3, add_dependency,        NOBUS },
+                { "add-requires",          MORE,  3, add_dependency,        NOBUS },
                 {}
         }, *verb = verbs;
 
@@ -6828,7 +7044,7 @@ static int runlevel_main(void) {
 }
 
 int main(int argc, char*argv[]) {
-        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        _cleanup_bus_close_unref_ sd_bus *bus = NULL;
         int r;
 
         setlocale(LC_ALL, "");