chiark / gitweb /
systemctl: fix exit statuses from is-active/is-failed
[elogind.git] / src / systemctl / systemctl.c
index 03b9dd9c20cc486c6ba7f329bca9f99077370941..ef0cbc5bf4ee980223d523efabf143c1443a17dd 100644 (file)
@@ -58,7 +58,6 @@
 #include "path-lookup.h"
 #include "conf-parser.h"
 #include "exit-status.h"
 #include "path-lookup.h"
 #include "conf-parser.h"
 #include "exit-status.h"
-#include "bus-errors.h"
 #include "build.h"
 #include "unit-name.h"
 #include "pager.h"
 #include "build.h"
 #include "unit-name.h"
 #include "pager.h"
@@ -68,6 +67,7 @@
 #include "logs-show.h"
 #include "socket-util.h"
 #include "fileio.h"
 #include "logs-show.h"
 #include "socket-util.h"
 #include "fileio.h"
+#include "env-util.h"
 #include "bus-util.h"
 #include "bus-message.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "bus-message.h"
 #include "bus-error.h"
@@ -135,6 +135,22 @@ static char *arg_host = NULL;
 static unsigned arg_lines = 10;
 static OutputMode arg_output = OUTPUT_SHORT;
 static bool arg_plain = false;
 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 int daemon_reload(sd_bus *bus, char **args);
 static int halt_now(enum action a);
 
 static int daemon_reload(sd_bus *bus, char **args);
 static int halt_now(enum action a);
@@ -1311,7 +1327,7 @@ static int list_dependencies_one(
                 char ***units,
                 unsigned int branches) {
 
                 char ***units,
                 unsigned int branches) {
 
-        _cleanup_strv_free_ char **deps = NULL, **u;
+        _cleanup_strv_free_ char **deps = NULL;
         char **c;
         int r = 0;
 
         char **c;
         int r = 0;
 
@@ -1319,8 +1335,8 @@ static int list_dependencies_one(
         assert(name);
         assert(units);
 
         assert(name);
         assert(units);
 
-        u = strv_append(*units, name);
-        if (!u)
+        r = strv_extend(units, name);
+        if (r < 0)
                 return log_oom();
 
         r = list_dependencies_get_dependencies(bus, name, &deps);
                 return log_oom();
 
         r = list_dependencies_get_dependencies(bus, name, &deps);
@@ -1332,7 +1348,7 @@ static int list_dependencies_one(
         STRV_FOREACH(c, deps) {
                 int state;
 
         STRV_FOREACH(c, deps) {
                 int state;
 
-                if (strv_contains(u, *c)) {
+                if (strv_contains(*units, *c)) {
                         if (!arg_plain) {
                                 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
                                 if (r < 0)
                         if (!arg_plain) {
                                 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
                                 if (r < 0)
@@ -1352,17 +1368,14 @@ static int list_dependencies_one(
                         return r;
 
                 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
                         return r;
 
                 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
-                       r = list_dependencies_one(bus, *c, level + 1, &u, (branches << 1) | (c[1] == NULL ? 0 : 1));
+                       r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (c[1] == NULL ? 0 : 1));
                        if (r < 0)
                                return r;
                 }
         }
 
                        if (r < 0)
                                return r;
                 }
         }
 
-        if (arg_plain) {
-                strv_free(*units);
-                *units = u;
-                u = NULL;
-        }
+        if (!arg_plain)
+                strv_remove(*units, name);
 
         return 0;
 }
 
         return 0;
 }
@@ -1375,7 +1388,7 @@ static int list_dependencies(sd_bus *bus, char **args) {
         assert(bus);
 
         if (args[1]) {
         assert(bus);
 
         if (args[1]) {
-                unit = unit_name_mangle(args[1], false);
+                unit = unit_name_mangle(args[1], MANGLE_NOGLOB);
                 if (!unit)
                         return log_oom();
                 u = unit;
                 if (!unit)
                         return log_oom();
                 u = unit;
@@ -1475,7 +1488,7 @@ static int set_default(sd_bus *bus, char **args) {
         unsigned n_changes = 0;
         int r;
 
         unsigned n_changes = 0;
         int r;
 
-        unit = unit_name_mangle_with_suffix(args[1], false, ".target");
+        unit = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
         if (!unit)
                 return log_oom();
 
         if (!unit)
                 return log_oom();
 
@@ -1924,7 +1937,7 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states
 
         assert(name);
 
 
         assert(name);
 
-        n = unit_name_mangle(name, false);
+        n = unit_name_mangle(name, MANGLE_NOGLOB);
         if (!n)
                 return log_oom();
 
         if (!n)
                 return log_oom();
 
@@ -1981,7 +1994,7 @@ static int check_triggering_units(
         char **i;
         int r;
 
         char **i;
         int r;
 
-        n = unit_name_mangle(name, false);
+        n = unit_name_mangle(name, MANGLE_NOGLOB);
         if (!n)
                 return log_oom();
 
         if (!n)
                 return log_oom();
 
@@ -2039,6 +2052,26 @@ static int check_triggering_units(
         return 0;
 }
 
         return 0;
 }
 
+static const char *verb_to_method(const char *verb) {
+       uint i;
+
+       for (i = 0; i < ELEMENTSOF(unit_actions); i++)
+                if (streq_ptr(unit_actions[i].verb, verb))
+                        return unit_actions[i].method;
+
+       return "StartUnit";
+}
+
+static const char *method_to_verb(const char *method) {
+       uint i;
+
+       for (i = 0; i < ELEMENTSOF(unit_actions); i++)
+                if (streq_ptr(unit_actions[i].method, method))
+                        return unit_actions[i].verb;
+
+       return "n/a";
+}
+
 static int start_unit_one(
                 sd_bus *bus,
                 const char *method,
 static int start_unit_one(
                 sd_bus *bus,
                 const char *method,
@@ -2067,12 +2100,16 @@ static int start_unit_one(
                         &reply,
                         "ss", name, mode);
         if (r < 0) {
                         &reply,
                         "ss", name, mode);
         if (r < 0) {
+                const char *verb;
+
                 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
                         /* There's always a fallback possible for
                          * legacy actions. */
                         return -EADDRNOTAVAIL;
 
                 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
                         /* There's always a fallback possible for
                          * legacy actions. */
                         return -EADDRNOTAVAIL;
 
-                log_error("Failed to %s %s: %s", method, name, bus_error_message(error, r));
+                verb = method_to_verb(method);
+
+                log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
                 return r;
         }
 
                 return r;
         }
 
@@ -2111,9 +2148,9 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
                 char *t;
 
                 if (suffix)
                 char *t;
 
                 if (suffix)
-                        t = unit_name_mangle_with_suffix(*name, true, suffix);
+                        t = unit_name_mangle_with_suffix(*name, MANGLE_GLOB, suffix);
                 else
                 else
-                        t = unit_name_mangle(*name, true);
+                        t = unit_name_mangle(*name, MANGLE_GLOB);
                 if (!t)
                         return log_oom();
 
                 if (!t)
                         return log_oom();
 
@@ -2191,21 +2228,7 @@ static int start_unit(sd_bus *bus, char **args) {
 
         if (arg_action == ACTION_SYSTEMCTL) {
                 enum action action;
 
         if (arg_action == ACTION_SYSTEMCTL) {
                 enum action action;
-                method =
-                        streq(args[0], "stop") ||
-                        streq(args[0], "condstop")              ? "StopUnit" :
-                        streq(args[0], "reload")                ? "ReloadUnit" :
-                        streq(args[0], "restart")               ? "RestartUnit" :
-
-                        streq(args[0], "try-restart")           ||
-                        streq(args[0], "condrestart")           ? "TryRestartUnit" :
-
-                        streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
-
-                        streq(args[0], "reload-or-try-restart") ||
-                        streq(args[0], "condreload")            ||
-                        streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
-                                                                  "StartUnit";
+                method = verb_to_method(args[0]);
                 action = verb_to_action(args[0]);
 
                 mode = streq(args[0], "isolate") ? "isolate" :
                 action = verb_to_action(args[0]);
 
                 mode = streq(args[0], "isolate") ? "isolate" :
@@ -2486,17 +2509,18 @@ static int start_special(sd_bus *bus, char **args) {
 }
 
 static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) {
 }
 
 static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_strv_free_ char **names = NULL;
         char **name;
         _cleanup_strv_free_ char **names = NULL;
         char **name;
-        int r = code;
+        int r;
 
         assert(bus);
         assert(args);
 
         r = expand_names(bus, args, NULL, &names);
 
         assert(bus);
         assert(args);
 
         r = expand_names(bus, args, NULL, &names);
-        if (r < 0)
+        if (r < 0) {
                 log_error("Failed to expand names: %s", strerror(-r));
                 log_error("Failed to expand names: %s", strerror(-r));
+                return r;
+        }
 
         STRV_FOREACH(name, names) {
                 int state;
 
         STRV_FOREACH(name, names) {
                 int state;
@@ -2504,8 +2528,8 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch
                 state = check_one_unit(bus, *name, good_states, arg_quiet);
                 if (state < 0)
                         return state;
                 state = check_one_unit(bus, *name, good_states, arg_quiet);
                 if (state < 0)
                         return state;
-                if (state > 0)
-                        r = 0;
+                if (state == 0)
+                        r = code;
         }
 
         return r;
         }
 
         return r;
@@ -3382,6 +3406,48 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                         if (arg_all || !isempty(a) || !isempty(b))
                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
 
                         if (arg_all || !isempty(a) || !isempty(b))
                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
 
+                        return 0;
+                } else if (streq_ptr(name, "SystemCallFilter")) {
+                        _cleanup_strv_free_ char **l = NULL;
+                        int whitelist;
+
+                        r = sd_bus_message_enter_container(m, 'r', "bas");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read(m, "b", &whitelist);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read_strv(m, &l);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (arg_all || whitelist || !strv_isempty(l)) {
+                                bool first = true;
+                                char **i;
+
+                                fputs(name, stdout);
+                                fputc('=', stdout);
+
+                                if (!whitelist)
+                                        fputc('~', stdout);
+
+                                STRV_FOREACH(i, l) {
+                                        if (first)
+                                                first = false;
+                                        else
+                                                fputc(' ', stdout);
+
+                                        fputs(*i, stdout);
+                                }
+                                fputc('\n', stdout);
+                        }
+
                         return 0;
                 }
 
                         return 0;
                 }
 
@@ -4117,7 +4183,7 @@ static int set_property(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
         if (r < 0)
                 return bus_log_create_error(r);
 
-        n = unit_name_mangle(args[1], false);
+        n = unit_name_mangle(args[1], MANGLE_NOGLOB);
         if (!n)
                 return log_oom();
 
         if (!n)
                 return log_oom();
 
@@ -4164,7 +4230,7 @@ static int snapshot(sd_bus *bus, char **args) {
         int r;
 
         if (strv_length(args) > 1)
         int r;
 
         if (strv_length(args) > 1)
-                n = unit_name_mangle_with_suffix(args[1], false, ".snapshot");
+                n = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".snapshot");
         else
                 n = strdup("");
         if (!n)
         else
                 n = strdup("");
         if (!n)
@@ -4445,6 +4511,69 @@ static int set_environment(sd_bus *bus, char **args) {
         return 0;
 }
 
         return 0;
 }
 
+static int import_environment(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;
+        int r;
+
+        assert(bus);
+        assert(args);
+
+        r = sd_bus_message_new_method_call(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "SetEnvironment",
+                        &m);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        if (strv_isempty(args + 1))
+                r = sd_bus_message_append_strv(m, environ);
+        else {
+                char **a, **b;
+
+                r = sd_bus_message_open_container(m, 'a', "s");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                STRV_FOREACH(a, args + 1) {
+
+                        if (!env_name_is_valid(*a)) {
+                                log_error("Not a valid environment variable name: %s", *a);
+                                return -EINVAL;
+                        }
+
+                        STRV_FOREACH(b, environ) {
+                                const char *eq;
+
+                                eq = startswith(*b, *a);
+                                if (eq && *eq == '=') {
+
+                                        r = sd_bus_message_append(m, "s", *b);
+                                        if (r < 0)
+                                                return bus_log_create_error(r);
+
+                                        break;
+                                }
+                        }
+                }
+
+                r = sd_bus_message_close_container(m);
+        }
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, 0, &error, NULL);
+        if (r < 0) {
+                log_error("Failed to import environment: %s", bus_error_message(&error, r));
+                return r;
+        }
+
+        return 0;
+}
+
 static int enable_sysv_units(const char *verb, char **args) {
         int r = 0;
 
 static int enable_sysv_units(const char *verb, char **args) {
         int r = 0;
 
@@ -4619,7 +4748,7 @@ static int mangle_names(char **original_names, char ***mangled_names) {
                 if (is_path(*name))
                         *i = strdup(*name);
                 else
                 if (is_path(*name))
                         *i = strdup(*name);
                 else
-                        *i = unit_name_mangle(*name, false);
+                        *i = unit_name_mangle(*name, MANGLE_NOGLOB);
 
                 if (!*i) {
                         strv_free(l);
 
                 if (!*i) {
                         strv_free(l);
@@ -4654,6 +4783,11 @@ static int enable_unit(sd_bus *bus, char **args) {
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
+        /* If the operation was fully executed by the SysV compat,
+         * let's finish early */
+        if (strv_isempty(names))
+                return 0;
+
         if (!bus || avoid_bus()) {
                 if (streq(verb, "enable")) {
                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
         if (!bus || avoid_bus()) {
                 if (streq(verb, "enable")) {
                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
@@ -4949,7 +5083,8 @@ static int systemctl_help(void) {
                "Environment Commands:\n"
                "  show-environment                Dump environment\n"
                "  set-environment NAME=VALUE...   Set one or more environment variables\n"
                "Environment Commands:\n"
                "  show-environment                Dump environment\n"
                "  set-environment NAME=VALUE...   Set one or more environment variables\n"
-               "  unset-environment NAME...       Unset one or more environment variables\n\n"
+               "  unset-environment NAME...       Unset one or more environment variables\n"
+               "  import-environment NAME...      Import all, one or more environment variables\n\n"
                "Manager Lifecycle Commands:\n"
                "  daemon-reload                   Reload systemd manager configuration\n"
                "  daemon-reexec                   Reexecute systemd manager\n\n"
                "Manager Lifecycle Commands:\n"
                "  daemon-reload                   Reload systemd manager configuration\n"
                "  daemon-reexec                   Reexecute systemd manager\n\n"
@@ -5915,6 +6050,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
                 { "show-environment",      EQUAL, 1, show_environment  },
                 { "set-environment",       MORE,  2, set_environment   },
                 { "unset-environment",     MORE,  2, set_environment   },
                 { "show-environment",      EQUAL, 1, show_environment  },
                 { "set-environment",       MORE,  2, set_environment   },
                 { "unset-environment",     MORE,  2, set_environment   },
+                { "import-environment",    MORE,  1, import_environment},
                 { "halt",                  EQUAL, 1, start_special,    FORCE },
                 { "poweroff",              EQUAL, 1, start_special,    FORCE },
                 { "reboot",                EQUAL, 1, start_special,    FORCE },
                 { "halt",                  EQUAL, 1, start_special,    FORCE },
                 { "poweroff",              EQUAL, 1, start_special,    FORCE },
                 { "reboot",                EQUAL, 1, start_special,    FORCE },