X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=418a80b6f0375e064ca5cd738e9291901f47a5a8;hp=becd68ff6e8215dcd33ad4572e24b92a65651958;hb=5522a1fa876f1ab94a2accaadca824799fdf2cab;hpb=265a7a2a604a9cf92e8aa167ed48afb78e6602ea diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index becd68ff6..418a80b6f 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1045,7 +1045,7 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { if (!n) return log_oom(); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -1336,7 +1336,9 @@ static void check_triggering_units( _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub; const char *interface = "org.freedesktop.systemd1.Unit", - *triggered_by_property = "TriggeredBy"; + *load_state_property = "LoadState", + *triggered_by_property = "TriggeredBy", + *state; char _cleanup_free_ *unit_path = NULL, *n = NULL; bool print_warning_label = true; int r; @@ -1353,6 +1355,41 @@ static void check_triggering_units( return; } + r = bus_method_call_with_reply( + bus, + "org.freedesktop.systemd1", + unit_path, + "org.freedesktop.DBus.Properties", + "Get", + &reply, + NULL, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_STRING, &load_state_property, + DBUS_TYPE_INVALID); + if (r < 0) + return; + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { + log_error("Failed to parse reply."); + return; + } + + dbus_message_iter_recurse(&iter, &sub); + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { + log_error("Failed to parse reply."); + return; + } + + dbus_message_iter_get_basic(&sub, &state); + + if (streq(state, "masked")) + return; + + dbus_message_unref(reply); + reply = NULL; + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", @@ -1481,53 +1518,39 @@ static int start_unit_one( return 0; } +static const struct { + const char *target; + const char *verb; + const char *mode; +} action_table[_ACTION_MAX] = { + [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" }, + [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" }, + [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" }, + [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" }, + [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" }, + [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" }, + [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" }, + [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" }, + [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" }, + [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" }, + [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" }, + [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" }, +}; + static enum action verb_to_action(const char *verb) { - if (streq(verb, "halt")) - return ACTION_HALT; - else if (streq(verb, "poweroff")) - return ACTION_POWEROFF; - else if (streq(verb, "reboot")) - return ACTION_REBOOT; - else if (streq(verb, "kexec")) - return ACTION_KEXEC; - else if (streq(verb, "rescue")) - return ACTION_RESCUE; - else if (streq(verb, "emergency")) - return ACTION_EMERGENCY; - else if (streq(verb, "default")) - return ACTION_DEFAULT; - else if (streq(verb, "exit")) - return ACTION_EXIT; - else if (streq(verb, "suspend")) - return ACTION_SUSPEND; - else if (streq(verb, "hibernate")) - return ACTION_HIBERNATE; - else if (streq(verb, "hybrid-sleep")) - return ACTION_HYBRID_SLEEP; - else - return ACTION_INVALID; + enum action i; + + for (i = ACTION_INVALID; i < _ACTION_MAX; i++) + if (action_table[i].verb && streq(verb, action_table[i].verb)) + return i; + return ACTION_INVALID; } static int start_unit(DBusConnection *bus, char **args) { - static const char * const table[_ACTION_MAX] = { - [ACTION_HALT] = SPECIAL_HALT_TARGET, - [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET, - [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET, - [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET, - [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET, - [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET, - [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET, - [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET, - [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET, - [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET, - [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET, - [ACTION_EXIT] = SPECIAL_EXIT_TARGET, - [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET, - [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET, - [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET - }; - int r, ret = 0; const char *method, *mode, *one_name; Set _cleanup_set_free_free_ *s = NULL; @@ -1541,6 +1564,7 @@ static int start_unit(DBusConnection *bus, char **args) { ask_password_agent_open_if_enabled(); if (arg_action == ACTION_SYSTEMCTL) { + enum action action; method = streq(args[0], "stop") || streq(args[0], "condstop") ? "StopUnit" : @@ -1557,28 +1581,21 @@ static int start_unit(DBusConnection *bus, char **args) { streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" : "StartUnit"; + action = verb_to_action(args[0]); - mode = - (streq(args[0], "isolate") || - streq(args[0], "rescue") || - streq(args[0], "emergency")) ? "isolate" : arg_job_mode; + mode = streq(args[0], "isolate") ? "isolate" : + action_table[action].mode ?: arg_job_mode; - one_name = table[verb_to_action(args[0])]; + one_name = action_table[action].target; } else { - assert(arg_action < ELEMENTSOF(table)); - assert(table[arg_action]); + assert(arg_action < ELEMENTSOF(action_table)); + assert(action_table[arg_action].target); method = "StartUnit"; - mode = (arg_action == ACTION_EMERGENCY || - arg_action == ACTION_RESCUE || - arg_action == ACTION_RUNLEVEL2 || - arg_action == ACTION_RUNLEVEL3 || - arg_action == ACTION_RUNLEVEL4 || - arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace"; - - one_name = table[arg_action]; + mode = action_table[arg_action].mode; + one_name = action_table[arg_action].target; } if (!arg_no_block) { @@ -1801,12 +1818,7 @@ static int check_inhibitors(DBusConnection *bus, enum action a) { return 0; log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.", - a == ACTION_HALT ? "halt" : - a == ACTION_POWEROFF ? "poweroff" : - a == ACTION_REBOOT ? "reboot" : - a == ACTION_KEXEC ? "kexec" : - a == ACTION_SUSPEND ? "suspend" : - a == ACTION_HIBERNATE ? "hibernate" : "hybrid-sleep"); + action_table[a].verb); return -EPERM; #else @@ -1951,53 +1963,41 @@ static int kill_unit(DBusConnection *bus, char **args) { } static int set_cgroup(DBusConnection *bus, char **args) { - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - DBusError error; - const char *method; - DBusMessageIter iter; - int r; _cleanup_free_ char *n = NULL; - const char *runtime; + const char *method, *runtime; + char **argument; + int r; assert(bus); assert(args); - dbus_error_init(&error); - method = - streq(args[0], "set-cgroup") ? "SetUnitControlGroups" : - streq(args[0], "unset-group") ? "UnsetUnitControlGroups" - : "UnsetUnitControlGroupAttributes"; + streq(args[0], "set-cgroup") ? "SetUnitControlGroup" : + streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup" + : "UnsetUnitControlGroupAttribute"; + + runtime = arg_runtime ? "runtime" : "persistent"; n = unit_name_mangle(args[1]); if (!n) return log_oom(); - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - method); - if (!m) - return log_oom(); - - dbus_message_iter_init_append(m, &iter); - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n)) - return log_oom(); - - r = bus_append_strv_iter(&iter, args + 2); - if (r < 0) - return log_oom(); - - runtime = arg_runtime ? "runtime" : "persistent"; - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime)) - return log_oom(); + STRV_FOREACH(argument, args + 2) { - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - dbus_error_free(&error); - return -EIO; + r = bus_method_call_with_reply( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method, + NULL, + NULL, + DBUS_TYPE_STRING, &n, + DBUS_TYPE_STRING, argument, + DBUS_TYPE_STRING, &runtime, + DBUS_TYPE_INVALID); + if (r < 0) + return r; } return 0; @@ -2006,20 +2006,17 @@ static int set_cgroup(DBusConnection *bus, char **args) { static int set_cgroup_attr(DBusConnection *bus, char **args) { _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; DBusError error; - DBusMessageIter iter, sub, sub2; - char **x, **y; + DBusMessageIter iter; _cleanup_free_ char *n = NULL; const char *runtime; + int r; assert(bus); assert(args); dbus_error_init(&error); - if (strv_length(args) % 2 != 0) { - log_error("Expecting an uneven number of arguments!"); - return -EINVAL; - } + runtime = arg_runtime ? "runtime" : "persistent"; n = unit_name_mangle(args[1]); if (!n) @@ -2029,26 +2026,20 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) { "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "SetUnitControlGroupAttributes"); + "SetUnitControlGroupAttribute"); if (!m) return log_oom(); dbus_message_iter_init_append(m, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2])) return log_oom(); - STRV_FOREACH_PAIR(x, y, args + 2) { - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, x) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, y) || - !dbus_message_iter_close_container(&sub, &sub2)) - return log_oom(); - } + r = bus_append_strv_iter(&iter, args + 3); + if (r < 0) + return log_oom(); - runtime = arg_runtime ? "runtime" : "persistent"; - if (!dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime)) + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime)) return log_oom(); reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); @@ -2063,57 +2054,49 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) { static int get_cgroup_attr(DBusConnection *bus, char **args) { _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - DBusError error; - DBusMessageIter iter; - int r; _cleanup_free_ char *n = NULL; - _cleanup_strv_free_ char **list = NULL; - char **a; + char **argument; + int r; assert(bus); assert(args); - dbus_error_init(&error); - n = unit_name_mangle(args[1]); if (!n) return log_oom(); - m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnitControlGroupAttributes"); - if (!m) - return log_oom(); - - dbus_message_iter_init_append(m, &iter); - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n)) - return log_oom(); - - r = bus_append_strv_iter(&iter, args + 2); - if (r < 0) - return log_oom(); + STRV_FOREACH(argument, args + 2) { + _cleanup_strv_free_ char **list = NULL; + DBusMessageIter iter; + char **a; - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - log_error("Failed to issue method call: %s", bus_error_message(&error)); - dbus_error_free(&error); - return -EIO; - } + r = bus_method_call_with_reply( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnitControlGroupAttribute", + &reply, + NULL, + DBUS_TYPE_STRING, &n, + DBUS_TYPE_STRING, argument, + DBUS_TYPE_INVALID); + if (r < 0) + return r; - dbus_message_iter_init(reply, &iter); - r = bus_parse_strv_iter(&iter, &list); - if (r < 0) { - log_error("Failed to parse value list."); - return r; - } + dbus_message_iter_init(reply, &iter); + r = bus_parse_strv_iter(&iter, &list); + if (r < 0) { + log_error("Failed to parse value list."); + return r; + } - STRV_FOREACH(a, list) { - if (endswith(*a, "\n")) - fputs(*a, stdout); - else - puts(*a); + STRV_FOREACH(a, list) { + if (endswith(*a, "\n")) + fputs(*a, stdout); + else + puts(*a); + } } return 0; @@ -3968,21 +3951,20 @@ static int enable_unit(DBusConnection *bus, char **args) { } /* Try to reload if enabeld */ - if (!arg_no_reload) + if (!arg_no_reload && running_in_chroot() <= 0) r = daemon_reload(bus, args); } if (carries_install_info == 0) - log_warning( -"The unit files have no [Install] section. They are not meant to be enabled\n" -"using systemctl.\n" -"Possible reasons for having this kind of units are:\n" -"1) A unit may be statically enabled by being symlinked from another unit's\n" -" .wants/ or .requires/ directory.\n" -"2) A unit's purpose may be to act as a helper for some other unit which has\n" -" a requirement dependency on it.\n" -"3) A unit may be started when needed via activation (socket, path, timer,\n" -" D-Bus, udev, scripted systemctl call, ...).\n"); + log_warning("The unit files have no [Install] section. They are not meant to be enabled\n" + "using systemctl.\n" + "Possible reasons for having this kind of units are:\n" + "1) A unit may be statically enabled by being symlinked from another unit's\n" + " .wants/ or .requires/ directory.\n" + "2) A unit's purpose may be to act as a helper for some other unit which has\n" + " a requirement dependency on it.\n" + "3) A unit may be started when needed via activation (socket, path, timer,\n" + " D-Bus, udev, scripted systemctl call, ...).\n"); finish: unit_file_changes_free(changes, n_changes); @@ -4268,6 +4250,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { enum { ARG_FAIL = 0x100, + ARG_IRREVERSIBLE, ARG_IGNORE_DEPENDENCIES, ARG_VERSION, ARG_USER, @@ -4296,6 +4279,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "failed", no_argument, NULL, ARG_FAILED }, { "full", no_argument, NULL, ARG_FULL }, { "fail", no_argument, NULL, ARG_FAIL }, + { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, { "ignore-inhibitors", no_argument, NULL, 'i' }, { "user", no_argument, NULL, ARG_USER }, @@ -4357,18 +4341,33 @@ static int systemctl_parse_argv(int argc, char *argv[]) { log_info("Use -t help to see a list of allowed values."); return -EINVAL; case 'p': { - char **l; + char *word, *state; + size_t size; + /* Make sure that if the empty property list + was specified, we won't show any properties. */ + const char *source = isempty(optarg) ? " " : optarg; + + FOREACH_WORD_SEPARATOR(word, size, source, ",", state) { + char _cleanup_free_ *prop; + char **tmp; + + prop = strndup(word, size); + if (!prop) + return -ENOMEM; - if (!(l = strv_append(arg_property, optarg))) - return -ENOMEM; + tmp = strv_append(arg_property, prop); + if (!tmp) + return -ENOMEM; - strv_free(arg_property); - arg_property = l; + strv_free(arg_property); + arg_property = tmp; + } /* If the user asked for a particular * property, show it to him, even if it is * empty. */ arg_all = true; + break; } @@ -4380,6 +4379,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_job_mode = "fail"; break; + case ARG_IRREVERSIBLE: + arg_job_mode = "replace-irreversibly"; + break; + case ARG_IGNORE_DEPENDENCIES: arg_job_mode = "ignore-dependencies"; break; @@ -5091,11 +5094,11 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */ { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */ { "isolate", EQUAL, 2, start_unit }, - { "set-cgroup", MORE, 2, set_cgroup }, - { "unset-cgroup", MORE, 2, set_cgroup }, - { "get-cgroup-attr", MORE, 2, get_cgroup_attr }, - { "set-cgroup-attr", MORE, 2, set_cgroup_attr }, - { "unset-cgroup-attr", MORE, 2, set_cgroup }, + { "set-cgroup", MORE, 3, set_cgroup }, + { "unset-cgroup", MORE, 3, set_cgroup }, + { "get-cgroup-attr", MORE, 3, get_cgroup_attr }, + { "set-cgroup-attr", MORE, 4, set_cgroup_attr }, + { "unset-cgroup-attr", MORE, 3, set_cgroup }, { "kill", MORE, 2, kill_unit }, { "is-active", MORE, 2, check_unit_active }, { "check", MORE, 2, check_unit_active },