X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=075ee4b752781e580e33d3ae58e698e6e9c76d65;hb=246aa6dd9dcea84bb945d16ec86e69f869dbb9b4;hp=ba4f171fdafe44147add6d0ae7fb0512d6acd4fc;hpb=bbb8486e1709ee297a1eb803f88041e1da1fa436;p=elogind.git diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index ba4f171fd..075ee4b75 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -78,6 +78,7 @@ static bool arg_no_pager = false; static bool arg_no_wtmp = false; static bool arg_no_wall = false; static bool arg_no_reload = false; +static bool arg_ignore_inhibitors = false; static bool arg_dry = false; static bool arg_quiet = false; static bool arg_full = false; @@ -1032,12 +1033,14 @@ finish: } static int load_unit(DBusConnection *bus, char **args) { - int r = 0; - char **name, *n; + char **name; assert(args); STRV_FOREACH(name, args+1) { + _cleanup_free_ char *n = NULL; + int r; + n = unit_name_mangle(*name); r = bus_method_call_with_reply ( bus, @@ -1049,18 +1052,14 @@ static int load_unit(DBusConnection *bus, char **args) { NULL, DBUS_TYPE_STRING, n ? &n : name, DBUS_TYPE_INVALID); - free(n); - if (r) - goto finish; + if (r < 0) + return r; } -finish: - return r; + return 0; } static int cancel_job(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; - int r = 0; char **name; assert(args); @@ -1069,54 +1068,30 @@ static int cancel_job(DBusConnection *bus, char **args) { return daemon_reload(bus, args); STRV_FOREACH(name, args+1) { - unsigned id; - const char *path; + uint32_t id; + int r; - r = safe_atou(*name, &id); + r = safe_atou32(*name, &id); if (r < 0) { log_error("Failed to parse job id: %s", strerror(-r)); - goto finish; + return r; } - assert_cc(sizeof(uint32_t) == sizeof(id)); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "GetJob", - &reply, - NULL, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_INVALID); - if (r) - goto finish; - - if (!dbus_message_get_args(reply, NULL, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply"); - dbus_message_unref(reply); - r = -EIO; - goto finish; - } - dbus_message_unref(reply); - - r = bus_method_call_with_reply ( - bus, - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Job", - "Cancel", + "CancelJob", NULL, NULL, + DBUS_TYPE_UINT32, &id, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; } -finish: - return r; + return 0; } static bool need_daemon_reload(DBusConnection *bus, const char *unit) { @@ -1366,20 +1341,25 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) { return r; } -static int check_one_unit(DBusConnection *bus, char *name, bool quiet) { - DBusMessage *reply = NULL; +static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) { + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub; const char *interface = "org.freedesktop.systemd1.Unit", *property = "ActiveState"; - const char *path = NULL; - const char *state; + const char *state, *path; + _cleanup_free_ char *n = NULL; + DBusError error; int r; - char *n; assert(name); + dbus_error_init(&error); + n = unit_name_mangle(name); + if (!n) + return log_oom(); + r = bus_method_call_with_reply ( bus, "org.freedesktop.systemd1", @@ -1387,26 +1367,28 @@ static int check_one_unit(DBusConnection *bus, char *name, bool quiet) { "org.freedesktop.systemd1.Manager", "GetUnit", &reply, - NULL, - DBUS_TYPE_STRING, n ? &n : &name, + &error, + DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID); - free(n); - if (r) { - if ((r != -ENOMEM) && (!quiet)) + if (r < 0) { + dbus_error_free(&error); + + if (!quiet) puts("unknown"); - goto finish; + return 0; } if (!dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return -EIO; } dbus_message_unref(reply); - r = bus_method_call_with_reply ( + reply = NULL; + + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", path, @@ -1417,22 +1399,23 @@ static int check_one_unit(DBusConnection *bus, char *name, bool quiet) { DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) { + if (!quiet) + puts("unknown"); + return 0; + } if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return r; } dbus_message_iter_recurse(&iter, &sub); if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { log_error("Failed to parse reply."); - r = -EIO; - goto finish; + return r; } dbus_message_iter_get_basic(&sub, &state); @@ -1440,16 +1423,7 @@ static int check_one_unit(DBusConnection *bus, char *name, bool quiet) { if (!quiet) puts(state); - if (streq(state, "active") || streq(state, "reloading")) - r = 0; - else - r = 3; /* According to LSB: "program is not running" */ - -finish: - if (reply) - dbus_message_unref(reply); - - return r; + return strv_find(check_states, state) ? 1 : 0; } static void check_triggering_units( @@ -1458,7 +1432,6 @@ static void check_triggering_units( _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub; - char *service_trigger = NULL; const char *interface = "org.freedesktop.systemd1.Unit", *triggered_by_property = "TriggeredBy"; @@ -1478,7 +1451,7 @@ static void check_triggering_units( return; } - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", unit_path, @@ -1489,7 +1462,7 @@ static void check_triggering_units( DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &triggered_by_property, DBUS_TYPE_INVALID); - if (r) + if (r < 0) return; if (!dbus_message_iter_init(reply, &iter) || @@ -1503,6 +1476,12 @@ static void check_triggering_units( sub = iter; while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + const char * const check_states[] = { + "active", + "reloading", + NULL + }; + const char *service_trigger; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { log_error("Failed to parse reply."); @@ -1511,14 +1490,15 @@ static void check_triggering_units( dbus_message_iter_get_basic(&sub, &service_trigger); - r = check_one_unit(bus, service_trigger, true); + r = check_one_unit(bus, service_trigger, (char**) check_states, true); if (r < 0) return; - if (r == 0) { + if (r > 0) { if (print_warning_label) { log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name); print_warning_label = false; } + log_warning(" %s", service_trigger); } @@ -1758,6 +1738,9 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) { const char *method; dbus_bool_t interactive = true; + if (!bus) + return -EIO; + polkit_agent_open_if_enabled(); switch (a) { @@ -1801,6 +1784,113 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) { #endif } +static int check_inhibitors(DBusConnection *bus, enum action a) { +#ifdef HAVE_LOGIND + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + DBusMessageIter iter, sub, sub2; + int r; + unsigned c = 0; + + if (!bus) + return 0; + + if (arg_ignore_inhibitors || arg_force > 0) + return 0; + + if (arg_when > 0) + return 0; + + if (geteuid() == 0) + return 0; + + if (!on_tty()) + return 0; + + r = bus_method_call_with_reply( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ListInhibitors", + &reply, + NULL, + DBUS_TYPE_INVALID); + if (r < 0) + /* If logind is not around, then there are no inhibitors... */ + return 0; + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + return -EIO; + } + + dbus_message_iter_recurse(&iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + const char *what, *who, *why, *mode; + uint32_t uid, pid; + _cleanup_strv_free_ char **sv = NULL; + _cleanup_free_ char *comm = NULL; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + return -EIO; + } + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) { + log_error("Failed to parse reply."); + return -EIO; + } + + if (!streq(mode, "block")) + goto next; + + sv = strv_split(what, ":"); + if (!sv) + return log_oom(); + + if (!strv_contains(sv, + a == ACTION_HALT || + a == ACTION_POWEROFF || + a == ACTION_REBOOT || + a == ACTION_KEXEC ? "shutdown" : "sleep")) + goto next; + + get_process_comm(pid, &comm); + log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", UID %lu), reason is \"%s\".", who, (unsigned long) pid, strna(comm), (unsigned long) uid, why); + c++; + + next: + dbus_message_iter_next(&sub); + } + + dbus_message_iter_recurse(&iter, &sub); + + if (c <= 0) + return 0; + + log_error("Please try again after closing inhibitors or ignore them 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"); + + return -EPERM; +#else + return 0; +#endif +} + static int start_special(DBusConnection *bus, char **args) { enum action a; int r; @@ -1809,6 +1899,10 @@ static int start_special(DBusConnection *bus, char **args) { a = verb_to_action(args[0]); + r = check_inhibitors(bus, a); + if (r < 0) + return r; + if (arg_force >= 2 && geteuid() != 0) { log_error("Must be root."); return -EPERM; @@ -1847,7 +1941,13 @@ static int start_special(DBusConnection *bus, char **args) { return r; } -static int check_unit(DBusConnection *bus, char **args) { +static int check_unit_active(DBusConnection *bus, char **args) { + const char * const check_states[] = { + "active", + "reloading", + NULL + }; + char **name; int r = 3; /* According to LSB: "program is not running" */ @@ -1855,10 +1955,37 @@ static int check_unit(DBusConnection *bus, char **args) { assert(args); STRV_FOREACH(name, args+1) { - int state = check_one_unit(bus, *name, arg_quiet); + int state; + + state = check_one_unit(bus, *name, (char**) check_states, arg_quiet); if (state < 0) return state; - if (state == 0) + if (state > 0) + r = 0; + } + + return r; +} + +static int check_unit_failed(DBusConnection *bus, char **args) { + const char * const check_states[] = { + "failed", + NULL + }; + + char **name; + int r = 1; + + assert(bus); + assert(args); + + STRV_FOREACH(name, args+1) { + int state; + + state = check_one_unit(bus, *name, (char**) check_states, arg_quiet); + if (state < 0) + return state; + if (state > 0) r = 0; } @@ -1866,17 +1993,21 @@ static int check_unit(DBusConnection *bus, char **args) { } static int kill_unit(DBusConnection *bus, char **args) { + char **name; int r = 0; - char **name, *n; + assert(bus); assert(args); if (!arg_kill_who) arg_kill_who = "all"; STRV_FOREACH(name, args+1) { + _cleanup_free_ char *n = NULL; + n = unit_name_mangle(*name); - r = bus_method_call_with_reply ( + + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -1888,13 +2019,116 @@ static int kill_unit(DBusConnection *bus, char **args) { DBUS_TYPE_STRING, &arg_kill_who, DBUS_TYPE_INT32, &arg_signal, DBUS_TYPE_INVALID); - free(n); - if (r) + if (r < 0) return r; } return 0; } +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; + + assert(bus); + assert(args); + + dbus_error_init(&error); + + method = + streq(args[0], "set-cgroup") ? "SetUnitControlGroups" : + streq(args[0], "unset-group") ? "UnsetUnitControlGroups" + : "UnsetUnitControlGroupAttributes"; + + 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(); + + 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; + } + + return 0; +} + +static int set_cgroup_attr(DBusConnection *bus, char **args) { + _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; + DBusError error; + DBusMessageIter iter, sub, sub2; + int r; + char **x, **y; + _cleanup_free_ char *n = NULL; + + assert(bus); + assert(args); + + dbus_error_init(&error); + + if (strv_length(args) % 2 != 0) { + log_error("Expecting an uneven number of arguments!"); + return -EINVAL; + } + + 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", + "SetUnitControlGroupAttributes"); + 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)) + 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(); + } + + if (!dbus_message_iter_close_container(&iter, &sub)) + return -ENOMEM; + + 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; + } + + return 0; +} + typedef struct ExecStatusInfo { char *name; @@ -2056,7 +2290,7 @@ static void print_status_info(UnitStatusInfo *i) { ExecStatusInfo *p; const char *on, *off, *ss; usec_t timestamp; - char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1; + char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1; char since2[FORMAT_TIMESTAMP_MAX], *s2; const char *path; @@ -2265,7 +2499,8 @@ static void print_status_info(UnitStatusInfo *i) { if (i->status_text) printf("\t Status: \"%s\"\n", i->status_text); - if (i->default_control_group) { + if (i->default_control_group && + (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) { unsigned c; printf("\t CGroup: %s\n", i->default_control_group); @@ -3036,7 +3271,7 @@ finish: } static int snapshot(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusError error; int r; dbus_bool_t cleanup = FALSE; @@ -3045,14 +3280,15 @@ static int snapshot(DBusConnection *bus, char **args) { *name = "", *path, *id, *interface = "org.freedesktop.systemd1.Unit", *property = "Id"; - char *n; + _cleanup_free_ char *n = NULL; dbus_error_init(&error); - if (strv_length(args) > 1) + if (strv_length(args) > 1) { name = args[1]; + n = unit_name_mangle(name); + } - n = unit_name_mangle(name); r = bus_method_call_with_reply ( bus, "org.freedesktop.systemd1", @@ -3064,8 +3300,7 @@ static int snapshot(DBusConnection *bus, char **args) { DBUS_TYPE_STRING, n ? (const char**) &n : &name, DBUS_TYPE_BOOLEAN, &cleanup, DBUS_TYPE_INVALID); - free(n); - if (r) + if (r < 0) goto finish; if (!dbus_message_get_args(reply, &error, @@ -3077,6 +3312,8 @@ static int snapshot(DBusConnection *bus, char **args) { } dbus_message_unref(reply); + reply = NULL; + r = bus_method_call_with_reply ( bus, "org.freedesktop.systemd1", @@ -3088,7 +3325,7 @@ static int snapshot(DBusConnection *bus, char **args) { DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); - if (r) + if (r < 0) goto finish; if (!dbus_message_iter_init(reply, &iter) || @@ -3112,69 +3349,36 @@ static int snapshot(DBusConnection *bus, char **args) { puts(id); finish: - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return r; } static int delete_snapshot(DBusConnection *bus, char **args) { - DBusMessage *reply = NULL; - int r = 0; - DBusError error; char **name; assert(args); - dbus_error_init(&error); - STRV_FOREACH(name, args+1) { - const char *path = NULL; - char *n; + _cleanup_free_ char *n = NULL; + int r; n = unit_name_mangle(*name); - r = bus_method_call_with_reply ( + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "GetUnit", - &reply, - NULL, - DBUS_TYPE_STRING, n ? &n : name, - DBUS_TYPE_INVALID); - free(n); - if (r) - goto finish; - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - r = -EIO; - dbus_message_unref(reply); - dbus_error_free(&error); - goto finish; - } - dbus_message_unref(reply); - - r = bus_method_call_with_reply ( - bus, - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Snapshot", - "Remove", + "RemoveSnapshot", NULL, NULL, + DBUS_TYPE_STRING, n ? &n : name, DBUS_TYPE_INVALID); - if (r) - goto finish; + if (r < 0) + return r; } -finish: - return r; + return 0; } static int daemon_reload(DBusConnection *bus, char **args) { @@ -3323,7 +3527,8 @@ finish: static int switch_root(DBusConnection *bus, char **args) { unsigned l; - const char *root, *init; + const char *root; + _cleanup_free_ char *init = NULL; l = strv_length(args); if (l < 2 || l > 3) { @@ -3332,7 +3537,23 @@ static int switch_root(DBusConnection *bus, char **args) { } root = args[1]; - init = l >= 3 ? args[2] : ""; + + if (l >= 3) + init = strdup(args[2]); + else { + parse_env_file("/proc/cmdline", WHITESPACE, + "init", &init, + NULL); + + if (!init) + init = strdup(""); + + if (!init) + return log_oom(); + + } + + log_debug("switching root - root: %s; init: %s", root, init); return bus_method_call_with_reply ( bus, @@ -3355,6 +3576,7 @@ static int set_environment(DBusConnection *bus, char **args) { int r; assert(bus); + assert(args); dbus_error_init(&error); @@ -3393,7 +3615,7 @@ finish: static int enable_sysv_units(char **args) { int r = 0; -#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA)) +#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG) const char *verb = args[0]; unsigned f = 1, t = 1; LookupPaths paths; @@ -3782,7 +4004,16 @@ static int enable_unit(DBusConnection *bus, char **args) { } if (carries_install_info == 0) - log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl."); + 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: if (m) @@ -3900,6 +4131,8 @@ static int systemctl_help(void) { " pending\n" " --ignore-dependencies\n" " When queueing a new job, ignore all its dependencies\n" + " -i --ignore-inhibitors\n" + " 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" " -H --host=[USER@]HOST\n" @@ -3933,19 +4166,26 @@ static int systemctl_help(void) { " reload [NAME...] Reload one or more units\n" " restart [NAME...] Start or restart one or more units\n" " try-restart [NAME...] Restart one or more units if active\n" - " reload-or-restart [NAME...] Reload one or more units is possible,\n" + " reload-or-restart [NAME...] Reload one or more units if possible,\n" " otherwise start or restart\n" - " reload-or-try-restart [NAME...] Reload one or more units is possible,\n" + " reload-or-try-restart [NAME...] Reload one or more units if possible,\n" " otherwise restart if active\n" " isolate [NAME] Start one unit and stop all others\n" " kill [NAME...] Send signal to processes of a unit\n" " is-active [NAME...] Check whether units are active\n" + " is-failed [NAME...] Check whether units are failed\n" " status [NAME...|PID...] Show runtime status of one or more units\n" " show [NAME...|JOB...] Show properties of one or more\n" " units/jobs or the manager\n" " help [NAME...|PID...] Show manual for one or more units\n" " reset-failed [NAME...] Reset failed state for all, one, or more\n" " units\n" + " set-cgroup [NAME] [CGROUP...] Add unit to a control group\n" + " unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n" + " set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n" + " Set control group attribute\n" + " unset-cgroup-attr [NAME] [ATTR...]\n" + " Unset control group attribute\n" " load [NAME...] Load one or more units\n\n" "Unit File Commands:\n" " list-unit-files List installed unit files\n" @@ -4109,6 +4349,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "full", no_argument, NULL, ARG_FULL }, { "fail", no_argument, NULL, ARG_FAIL }, { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, + { "ignore-inhibitors", no_argument, NULL, 'i' }, { "user", no_argument, NULL, ARG_USER }, { "system", no_argument, NULL, ARG_SYSTEM }, { "global", no_argument, NULL, ARG_GLOBAL }, @@ -4138,7 +4379,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:i", options, NULL)) >= 0) { switch (c) { @@ -4148,7 +4389,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { case ARG_VERSION: puts(PACKAGE_STRING); - puts(DISTRIBUTION); puts(SYSTEMD_FEATURES); return 0; @@ -4305,6 +4545,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } break; + case 'i': + arg_ignore_inhibitors = true; + break; + case '?': return -EINVAL; @@ -4917,9 +5161,14 @@ 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 }, + { "set-cgroup-attr", MORE, 2, set_cgroup_attr }, + { "unset-cgroup-attr", MORE, 2, set_cgroup }, { "kill", MORE, 2, kill_unit }, - { "is-active", MORE, 2, check_unit }, - { "check", MORE, 2, check_unit }, + { "is-active", MORE, 2, check_unit_active }, + { "check", MORE, 2, check_unit_active }, + { "is-failed", MORE, 2, check_unit_failed }, { "show", MORE, 1, show }, { "status", MORE, 2, show }, { "help", MORE, 2, show }, @@ -5176,6 +5425,10 @@ static _noreturn_ void halt_now(enum action a) { static int halt_main(DBusConnection *bus) { int r; + r = check_inhibitors(bus, arg_action); + if (r < 0) + return r; + if (geteuid() != 0) { /* Try logind if we are a normal user and no special * mode applies. Maybe PolicyKit allows us to shutdown @@ -5183,7 +5436,7 @@ static int halt_main(DBusConnection *bus) { if (arg_when <= 0 && !arg_dry && - !arg_force && + arg_force <= 0 && (arg_action == ACTION_POWEROFF || arg_action == ACTION_REBOOT)) { r = reboot_with_logind(bus, arg_action);