X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=00cd2523517ca2182fefed9a6162c8fdcf8f96bc;hp=ae6113089d0c297b4fa6402eabcc551b1531afc9;hb=dfcc5c33f42554a5293e68e7093da2403e363997;hpb=48899192a7b28b6a338cc8ec18aa35ccd8867acb diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index ae6113089..00cd25235 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -65,6 +65,7 @@ #include "path-util.h" static const char *arg_type = NULL; +static const char *arg_load_state = NULL; static char **arg_property = NULL; static bool arg_all = false; static const char *arg_job_mode = "replace"; @@ -85,7 +86,6 @@ static bool arg_failed = false; static bool arg_runtime = false; static char **arg_wall = NULL; static const char *arg_kill_who = NULL; -static const char *arg_kill_mode = NULL; static int arg_signal = SIGTERM; static const char *arg_root = NULL; static usec_t arg_when = 0; @@ -247,12 +247,13 @@ static int translate_bus_error_to_exit_status(int r, const DBusError *error) { static void warn_wall(enum action a) { static const char *table[_ACTION_MAX] = { - [ACTION_HALT] = "The system is going down for system halt NOW!", - [ACTION_REBOOT] = "The system is going down for reboot NOW!", - [ACTION_POWEROFF] = "The system is going down for power-off NOW!", - [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!", - [ACTION_RESCUE] = "The system is going down to rescue mode NOW!", - [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!" + [ACTION_HALT] = "The system is going down for system halt NOW!", + [ACTION_REBOOT] = "The system is going down for reboot NOW!", + [ACTION_POWEROFF] = "The system is going down for power-off NOW!", + [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!", + [ACTION_RESCUE] = "The system is going down to rescue mode NOW!", + [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!", + [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!" }; if (arg_no_wall) @@ -337,7 +338,9 @@ static bool output_show_unit(const struct unit_info *u) { return (!arg_type || ((dot = strrchr(u->id, '.')) && streq(dot+1, arg_type))) && - (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0); + (!arg_load_state || streq(u->load_state, arg_load_state)) && + (arg_all || !(streq(u->active_state, "inactive") + || u->following[0]) || u->job_id > 0); } static void output_units_list(const struct unit_info *unit_infos, unsigned c) { @@ -655,10 +658,8 @@ static int list_unit_files(DBusConnection *bus, char **args) { Iterator i; h = hashmap_new(string_hash_func, string_compare_func); - if (!h) { - log_error("Out of memory"); - return -ENOMEM; - } + if (!h) + return log_oom(); r = unit_file_get_list(arg_scope, arg_root, h); if (r < 0) { @@ -671,8 +672,7 @@ static int list_unit_files(DBusConnection *bus, char **args) { units = new(UnitFileList, n_units); if (!units) { unit_file_list_free(h); - log_error("Out of memory"); - return -ENOMEM; + return log_oom(); } HASHMAP_FOREACH(u, h, i) { @@ -781,7 +781,7 @@ static int dot_one_property(const char *name, const char *prop, DBusMessageIter "RequiresOverridable", "[color=\"black\"]", "Requisite", "[color=\"darkblue\"]", "RequisiteOverridable", "[color=\"darkblue\"]", - "Wants", "[color=\"darkgrey\"]", + "Wants", "[color=\"grey66\"]", "Conflicts", "[color=\"red\"]", "ConflictedBy", "[color=\"red\"]", "After", "[color=\"green\"]" @@ -1123,6 +1123,8 @@ static int load_unit(DBusConnection *bus, char **args) { STRV_FOREACH(name, args+1) { DBusMessage *reply; + bool b; + char *n; if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", @@ -1134,15 +1136,19 @@ static int load_unit(DBusConnection *bus, char **args) { goto finish; } - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { + n = unit_name_mangle(*name); + b = dbus_message_append_args(m, + DBUS_TYPE_STRING, n ? &n : name, + DBUS_TYPE_INVALID); + free(n); + if (!b) { log_error("Could not append arguments to message."); r = -ENOMEM; goto finish; } - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + 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)); r = -EIO; goto finish; @@ -1266,22 +1272,29 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { *interface = "org.freedesktop.systemd1.Unit", *property = "NeedDaemonReload", *path; + char *n; + bool k; /* We ignore all errors here, since this is used to show a warning only */ - if (!(m = dbus_message_new_method_call( + m = dbus_message_new_method_call( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "GetUnit"))) + "GetUnit"); + if (!m) goto finish; - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &unit, - DBUS_TYPE_INVALID)) + n = unit_name_mangle(unit); + k = dbus_message_append_args(m, + DBUS_TYPE_STRING, n ? (const char**) &n : &unit, + DBUS_TYPE_INVALID); + free(n); + if (!k) goto finish; - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL))) + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL); + if (!reply) goto finish; if (!dbus_message_get_args(reply, NULL, @@ -1290,11 +1303,12 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { goto finish; dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.DBus.Properties", - "Get"))) + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + path, + "org.freedesktop.DBus.Properties", + "Get"); + if (!m) goto finish; if (!dbus_message_append_args(m, @@ -1305,7 +1319,8 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) { } dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL))) + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL); + if (!reply) goto finish; if (!dbus_message_iter_init(reply, &iter) || @@ -1510,6 +1525,8 @@ static int check_one_unit(DBusConnection *bus, char *name, bool quiet) { const char *path = NULL; const char *state; int r = 3; /* According to LSB: "program is not running" */ + char *n; + bool b; assert(bus); assert(name); @@ -1527,9 +1544,12 @@ static int check_one_unit(DBusConnection *bus, char *name, bool quiet) { goto finish; } - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) { + n = unit_name_mangle(name); + b = dbus_message_append_args(m, + DBUS_TYPE_STRING, n ? &n : &name, + DBUS_TYPE_INVALID); + free(n); + if (!b) { log_error("Could not append arguments to message."); r = -ENOMEM; goto finish; @@ -1627,12 +1647,14 @@ static void check_triggering_units( const char *interface = "org.freedesktop.systemd1.Unit", *triggered_by_property = "TriggeredBy"; - char *unit_path = NULL; + char *unit_path = NULL, *n = NULL; bool print_warning_label = true; dbus_error_init(&error); - unit_path = unit_dbus_path_from_name(unit_name); + n = unit_name_mangle(unit_name); + unit_path = unit_dbus_path_from_name(n ? n : unit_name); + free(n); if (!unit_path) { log_error("Could not allocate dbus path."); goto finish; @@ -1718,6 +1740,8 @@ static int start_unit_one( DBusMessage *m = NULL, *reply = NULL; const char *path; int r; + char *n; + bool b; assert(bus); assert(method); @@ -1726,26 +1750,31 @@ static int start_unit_one( assert(error); assert(arg_no_block || s); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - method))) { + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method); + if (!m) { log_error("Could not allocate message."); r = -ENOMEM; goto finish; } - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &mode, - DBUS_TYPE_INVALID)) { + n = unit_name_mangle(name); + b = dbus_message_append_args(m, + DBUS_TYPE_STRING, n ? (const char **) &n : &name, + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID); + free(n); + if (!b) { log_error("Could not append arguments to message."); r = -ENOMEM; goto finish; } - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) { + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error); + if (!reply) { if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) { /* There's always a fallback possible for @@ -2108,34 +2137,37 @@ static int kill_unit(DBusConnection *bus, char **args) { if (!arg_kill_who) arg_kill_who = "all"; - if (!arg_kill_mode) - arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process"; - STRV_FOREACH(name, args+1) { DBusMessage *reply; + char *n; + bool b; - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "KillUnit"))) { + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit"); + if (!m) { log_error("Could not allocate message."); r = -ENOMEM; goto finish; } - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_STRING, &arg_kill_who, - DBUS_TYPE_STRING, &arg_kill_mode, - DBUS_TYPE_INT32, &arg_signal, - DBUS_TYPE_INVALID)) { + n = unit_name_mangle(*name); + b = dbus_message_append_args(m, + DBUS_TYPE_STRING, n ? &n : name, + DBUS_TYPE_STRING, &arg_kill_who, + DBUS_TYPE_INT32, &arg_signal, + DBUS_TYPE_INVALID); + free(n); + if (!b) { log_error("Could not append arguments to message."); r = -ENOMEM; goto finish; } - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + 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); r = -EIO; @@ -2553,8 +2585,16 @@ static void print_status_info(UnitStatusInfo *i) { } if (i->id && arg_transport != TRANSPORT_SSH) { + int flags = + arg_lines * OUTPUT_SHOW_ALL | + arg_follow * OUTPUT_FOLLOW | + !arg_quiet * OUTPUT_WARN_CUTOFF | + on_tty() * OUTPUT_COLOR; + printf("\n"); - show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow); + show_journal_by_unit(i->id, arg_output, 0, + i->inactive_exit_timestamp_monotonic, + arg_lines, flags); } if (i->need_daemon_reload) @@ -2591,14 +2631,14 @@ static void show_unit_help(UnitStatusInfo *i) { if (e) { page = strndup((*p) + 4, e - *p - 4); if (!page) { - log_error("Out of memory."); + log_oom(); return; } section = strndup(e + 1, *p + k - e - 2); if (!section) { free(page); - log_error("Out of memory"); + log_oom(); return; } @@ -2627,7 +2667,7 @@ static void show_unit_help(UnitStatusInfo *i) { wait_for_terminate(pid, NULL); } else - log_info("Can't show %s.", *p); + log_info("Can't show: %s", *p); } } @@ -3237,12 +3277,14 @@ static int show(DBusConnection *bus, char **args) { uint32_t id; if (safe_atou32(*name, &id) < 0) { - + char *p, *n; /* Interpret as unit name */ - char *p = unit_dbus_path_from_name(*name); + n = unit_name_mangle(*name); + p = unit_dbus_path_from_name(n ? n : *name); + free(n); if (!p) - return -ENOMEM; + return log_oom(); r = show_one(args[0], bus, p, show_properties, &new_line); free(p); @@ -3256,7 +3298,7 @@ static int show(DBusConnection *bus, char **args) { char *p; if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) - return -ENOMEM; + return log_oom(); r = show_one(args[0], bus, p, show_properties, &new_line); free(p); @@ -3336,14 +3378,17 @@ static int snapshot(DBusConnection *bus, char **args) { const char *interface = "org.freedesktop.systemd1.Unit", *property = "Id"; + char *n; + bool b; dbus_error_init(&error); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "CreateSnapshot"))) { + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "CreateSnapshot"); + if (!m) { log_error("Could not allocate message."); return -ENOMEM; } @@ -3351,16 +3396,20 @@ static int snapshot(DBusConnection *bus, char **args) { if (strv_length(args) > 1) name = args[1]; - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_BOOLEAN, &cleanup, - DBUS_TYPE_INVALID)) { + n = unit_name_mangle(name); + b = dbus_message_append_args(m, + DBUS_TYPE_STRING, n ? (const char**) &n : &name, + DBUS_TYPE_BOOLEAN, &cleanup, + DBUS_TYPE_INVALID); + free(n); + if (!b) { log_error("Could not append arguments to message."); r = -ENOMEM; goto finish; } - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + 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)); r = -EIO; goto finish; @@ -3375,11 +3424,12 @@ static int snapshot(DBusConnection *bus, char **args) { } dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( + m = dbus_message_new_method_call( "org.freedesktop.systemd1", path, "org.freedesktop.DBus.Properties", - "Get"))) { + "Get"); + if (!m) { log_error("Could not allocate message."); return -ENOMEM; } @@ -3394,7 +3444,8 @@ static int snapshot(DBusConnection *bus, char **args) { } dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + 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)); r = -EIO; goto finish; @@ -3446,26 +3497,33 @@ static int delete_snapshot(DBusConnection *bus, char **args) { STRV_FOREACH(name, args+1) { const char *path = NULL; + char *n; + bool b; - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "GetUnit"))) { + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnit"); + if (!m) { log_error("Could not allocate message."); r = -ENOMEM; goto finish; } - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { + n = unit_name_mangle(*name); + b = dbus_message_append_args(m, + DBUS_TYPE_STRING, n ? &n : name, + DBUS_TYPE_INVALID); + free(n); + if (!b) { log_error("Could not append arguments to message."); r = -ENOMEM; goto finish; } - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + 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)); r = -EIO; goto finish; @@ -3480,18 +3538,20 @@ static int delete_snapshot(DBusConnection *bus, char **args) { } dbus_message_unref(m); - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Snapshot", - "Remove"))) { + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Snapshot", + "Remove"); + if (!m) { log_error("Could not allocate message."); r = -ENOMEM; goto finish; } dbus_message_unref(reply); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + 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)); r = -EIO; goto finish; @@ -3602,26 +3662,33 @@ static int reset_failed(DBusConnection *bus, char **args) { STRV_FOREACH(name, args+1) { DBusMessage *reply; + char *n; + bool b; - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "ResetFailedUnit"))) { + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ResetFailedUnit"); + if (!m) { log_error("Could not allocate message."); r = -ENOMEM; goto finish; } - if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, name, - DBUS_TYPE_INVALID)) { + n = unit_name_mangle(*name); + b = dbus_message_append_args(m, + DBUS_TYPE_STRING, n ? &n : name, + DBUS_TYPE_INVALID); + free(n); + if (!b) { log_error("Could not append arguments to message."); r = -ENOMEM; goto finish; } - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + 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)); r = -EIO; goto finish; @@ -3854,7 +3921,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_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA)) +#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA)) const char *verb = args[0]; unsigned f = 1, t = 1; LookupPaths paths; @@ -3904,8 +3971,7 @@ static int enable_sysv_units(char **args) { asprintf(&p, "%s/%s", *k, name); if (!p) { - log_error("No memory"); - r = -ENOMEM; + r = log_oom(); goto finish; } @@ -3925,8 +3991,7 @@ static int enable_sysv_units(char **args) { else asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name); if (!p) { - log_error("No memory"); - r = -ENOMEM; + r = log_oom(); goto finish; } @@ -3954,10 +4019,9 @@ static int enable_sysv_units(char **args) { l = strv_join((char**)argv, " "); if (!l) { - log_error("No memory."); free(q); free(p); - r = -ENOMEM; + r = log_oom(); goto finish; } @@ -4114,8 +4178,7 @@ static int enable_unit(DBusConnection *bus, char **args) { "org.freedesktop.systemd1.Manager", method); if (!m) { - log_error("Out of memory"); - r = -ENOMEM; + r = log_oom(); goto finish; } @@ -4209,7 +4272,7 @@ static int enable_unit(DBusConnection *bus, char **args) { } if (carries_install_info == 0) - log_warning("Warning: unit files do not carry install information. No operation executed."); + log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl."); finish: if (m) @@ -4269,8 +4332,7 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { "org.freedesktop.systemd1.Manager", "GetUnitFileState"); if (!m) { - log_error("Out of memory"); - r = -ENOMEM; + r = log_oom(); goto finish; } @@ -4518,7 +4580,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_ROOT, ARG_FULL, ARG_NO_RELOAD, - ARG_KILL_MODE, ARG_KILL_WHO, ARG_NO_ASK_PASSWORD, ARG_FAILED, @@ -4550,7 +4611,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "root", required_argument, NULL, ARG_ROOT }, { "force", no_argument, NULL, ARG_FORCE }, { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, - { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */ { "kill-who", required_argument, NULL, ARG_KILL_WHO }, { "signal", required_argument, NULL, 's' }, { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, @@ -4583,9 +4643,17 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return 0; case 't': - arg_type = optarg; - break; - + if (unit_type_from_string(optarg) >= 0) { + arg_type = optarg; + break; + } + if (unit_load_state_from_string(optarg) >= 0) { + arg_load_state = optarg; + break; + } + log_error("Unkown unit type or load state '%s'.", + optarg); + return -EINVAL; case 'p': { char **l; @@ -4688,10 +4756,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_kill_who = optarg; break; - case ARG_KILL_MODE: - arg_kill_mode = optarg; - break; - case 's': if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) { log_error("Failed to parse signal string %s.", optarg); @@ -4735,7 +4799,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return -EINVAL; default: - log_error("Unknown option code %c", c); + log_error("Unknown option code '%c'.", c); return -EINVAL; } } @@ -4828,7 +4892,7 @@ static int halt_parse_argv(int argc, char *argv[]) { return -EINVAL; default: - log_error("Unknown option code %c", c); + log_error("Unknown option code '%c'.", c); return -EINVAL; } } @@ -4965,12 +5029,12 @@ static int shutdown_parse_argv(int argc, char *argv[]) { return -EINVAL; default: - log_error("Unknown option code %c", c); + log_error("Unknown option code '%c'.", c); return -EINVAL; } } - if (argc > optind) { + if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) { r = parse_time_spec(argv[optind], &arg_when); if (r < 0) { log_error("Failed to parse time specification: %s", argv[optind]); @@ -4979,8 +5043,11 @@ static int shutdown_parse_argv(int argc, char *argv[]) { } else arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE; - /* We skip the time argument */ - if (argc > optind + 1) + if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN) + /* No time argument for shutdown cancel */ + arg_wall = argv + optind; + else if (argc > optind + 1) + /* We skip the time argument */ arg_wall = argv + optind + 1; optind = argc; @@ -5041,7 +5108,7 @@ static int telinit_parse_argv(int argc, char *argv[]) { return -EINVAL; default: - log_error("Unknown option code %c", c); + log_error("Unknown option code '%c'.", c); return -EINVAL; } } @@ -5066,7 +5133,7 @@ static int telinit_parse_argv(int argc, char *argv[]) { break; if (i >= ELEMENTSOF(table)) { - log_error("Unknown command %s.", argv[optind]); + log_error("Unknown command '%s'.", argv[optind]); return -EINVAL; } @@ -5104,7 +5171,7 @@ static int runlevel_parse_argv(int argc, char *argv[]) { return -EINVAL; default: - log_error("Unknown option code %c", c); + log_error("Unknown option code '%c'.", c); return -EINVAL; } } @@ -5405,7 +5472,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError break; if (i >= ELEMENTSOF(verbs)) { - log_error("Unknown operation %s", argv[optind]); + log_error("Unknown operation '%s'.", argv[optind]); return -EINVAL; } } @@ -5569,7 +5636,7 @@ done: return 0; } -static void halt_now(enum action a) { +static _noreturn_ void halt_now(enum action a) { /* Make sure C-A-D is handled by the kernel from this * point on... */ @@ -5759,9 +5826,22 @@ int main(int argc, char*argv[]) { r = reload_with_fallback(bus); break; - case ACTION_CANCEL_SHUTDOWN: - r = send_shutdownd(0, 0, false, false, NULL); + case ACTION_CANCEL_SHUTDOWN: { + char *m = NULL; + + if (arg_wall) { + m = strv_join(arg_wall, " "); + if (!m) { + retval = EXIT_FAILURE; + goto finish; + } + } + r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m); + if (r < 0) + log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r)); + free(m); break; + } case ACTION_INVALID: case ACTION_RUNLEVEL: