X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=34d70792990f122233665ab098b0cdb1f90c4d0b;hb=538b08707ab7d34fac5b8c2753d3bf9ac12c2ebf;hp=3a9bca90cec1aff20b1eba59189acac5f4d3d65d;hpb=f78e6385dc4cee0a1f399c4c89ebf823c108d447;p=elogind.git diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 3a9bca90c..34d707929 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -58,7 +58,6 @@ #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" @@ -68,6 +67,7 @@ #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" @@ -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 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); @@ -892,6 +908,31 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) { return 0; } +static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) { + usec_t next_elapse; + + assert(nw); + assert(next); + + if (next->monotonic != (usec_t) -1 && next->monotonic > 0) { + usec_t converted; + + if (next->monotonic > nw->monotonic) + converted = nw->realtime + (next->monotonic - nw->monotonic); + else + converted = nw->realtime - (nw->monotonic - next->monotonic); + + if (next->realtime != (usec_t) -1 && next->realtime > 0) + next_elapse = MIN(converted, next->realtime); + else + next_elapse = converted; + + } else + next_elapse = next->realtime; + + return next_elapse; +} + static int list_timers(sd_bus *bus, char **args) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; @@ -914,7 +955,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 = {}; usec_t m; if (!endswith(u->id, ".timer")) @@ -928,26 +969,13 @@ static int list_timers(sd_bus *bus, char **args) { if (r < 0) goto cleanup; - if (next.monotonic != (usec_t) -1 && next.monotonic > 0) { - usec_t converted; - - if (next.monotonic > nw.monotonic) - converted = nw.realtime + (next.monotonic - nw.monotonic); - else - converted = nw.realtime - (nw.monotonic - next.monotonic); - - if (next.realtime != (usec_t) -1 && next.realtime > 0) - m = MIN(converted, next.realtime); - else - m = converted; - } else - m = next.realtime; - if (!GREEDY_REALLOC(timer_infos, size, c+1)) { r = log_oom(); goto cleanup; } + m = calc_next_elapse(&nw, &next); + timer_infos[c++] = (struct timer_info) { .id = u->id, .next_elapse = m, @@ -1311,7 +1339,7 @@ static int list_dependencies_one( char ***units, unsigned int branches) { - _cleanup_strv_free_ char **deps = NULL, **u; + _cleanup_strv_free_ char **deps = NULL; char **c; int r = 0; @@ -1319,8 +1347,8 @@ static int list_dependencies_one( 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); @@ -1332,7 +1360,7 @@ static int list_dependencies_one( 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) @@ -1352,17 +1380,14 @@ static int list_dependencies_one( 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 (arg_plain) { - strv_free(*units); - *units = u; - u = NULL; - } + if (!arg_plain) + strv_remove(*units, name); return 0; } @@ -2039,6 +2064,26 @@ static int check_triggering_units( 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, @@ -2067,12 +2112,16 @@ static int start_unit_one( &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; - 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; } @@ -2191,21 +2240,7 @@ static int start_unit(sd_bus *bus, char **args) { 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" : @@ -2486,17 +2521,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) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_strv_free_ char **names = NULL; char **name; - int r = code; + int r; 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)); + return r; + } STRV_FOREACH(name, names) { int state; @@ -2504,8 +2540,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; - if (state > 0) - r = 0; + if (state == 0) + r = code; } return r; @@ -3382,6 +3418,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)); + 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; } @@ -3979,7 +4057,7 @@ static int append_assignment(sd_bus_message *m, const char *assignment) { } else if (streq(field, "MemoryLimit")) { off_t bytes; - r = parse_bytes(eq, &bytes); + r = parse_size(eq, 1024, &bytes); if (r < 0) { log_error("Failed to parse bytes specification %s", assignment); return -EINVAL; @@ -4049,7 +4127,7 @@ static int append_assignment(sd_bus_message *m, const char *assignment) { return -EINVAL; } - r = parse_bytes(bandwidth, &bytes); + r = parse_size(bandwidth, 1000, &bytes); if (r < 0) { log_error("Failed to parse byte value %s.", bandwidth); return -EINVAL; @@ -4109,11 +4187,11 @@ static int set_property(sd_bus *bus, char **args) { r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "SetUnitProperties", - &m); + "SetUnitProperties"); if (r < 0) return bus_log_create_error(r); @@ -4424,11 +4502,11 @@ static int set_environment(sd_bus *bus, char **args) { r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - method, - &m); + method); if (r < 0) return bus_log_create_error(r); @@ -4445,6 +4523,69 @@ static int set_environment(sd_bus *bus, char **args) { 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, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SetEnvironment"); + 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; @@ -4654,6 +4795,11 @@ static int enable_unit(sd_bus *bus, char **args) { 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); @@ -4715,11 +4861,11 @@ static int enable_unit(sd_bus *bus, char **args) { r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - method, - &m); + method); if (r < 0) return bus_log_create_error(r); @@ -4949,7 +5095,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" - " 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" @@ -5744,7 +5891,6 @@ static int runlevel_parse_argv(int argc, char *argv[]) { case ARG_HELP: return runlevel_help(); - return 0; case '?': return -EINVAL; @@ -5915,6 +6061,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 }, + { "import-environment", MORE, 1, import_environment}, { "halt", EQUAL, 1, start_special, FORCE }, { "poweroff", EQUAL, 1, start_special, FORCE }, { "reboot", EQUAL, 1, start_special, FORCE },