X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=69f157cebbc625db448ebd444ccfa21b1e10b8e1;hp=072f615ad547f18c152f45ec29d8a32a9460c8c4;hb=56f64d95763a799ba4475daf44d8e9f72a1bd474;hpb=fdbdf6ec29bda40763d7d3e7bb2a63e2f5d60c4c diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 072f615ad..69f157ceb 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -67,6 +67,7 @@ #include "logs-show.h" #include "socket-util.h" #include "fileio.h" +#include "copy.h" #include "env-util.h" #include "bus-util.h" #include "bus-message.h" @@ -137,23 +138,6 @@ 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 bool original_stdout_is_tty; static int daemon_reload(sd_bus *bus, char **args); @@ -318,21 +302,37 @@ static int compare_unit_info(const void *a, const void *b) { } static bool output_show_unit(const UnitInfo *u, char **patterns) { - const char *dot; - if (!strv_isempty(patterns)) { char **pattern; STRV_FOREACH(pattern, patterns) if (fnmatch(*pattern, u->id, FNM_NOESCAPE) == 0) - return true; + goto next; return false; } - return (!arg_types || ((dot = strrchr(u->id, '.')) && - strv_find(arg_types, dot+1))) && - (arg_all || !(streq(u->active_state, "inactive") - || u->following[0]) || u->job_id > 0); +next: + if (arg_types) { + const char *dot; + + dot = strrchr(u->id, '.'); + if (!dot) + return false; + + if (!strv_find(arg_types, dot+1)) + return false; + } + + if (arg_all) + return true; + + if (u->job_id > 0) + return true; + + if (streq(u->active_state, "inactive") || u->following[0]) + return false; + + return true; } static int output_units_list(const UnitInfo *unit_infos, unsigned c) { @@ -594,7 +594,7 @@ static int get_unit_list_recursive( assert(_unit_infos); assert(_machines); - replies = set_new(NULL, NULL); + replies = set_new(NULL); if (!replies) return log_oom(); @@ -622,7 +622,7 @@ static int get_unit_list_recursive( r = sd_bus_open_system_container(&container, *i); if (r < 0) { - log_error("Failed to connect to container %s: %s", *i, strerror(-r)); + log_error_errno(r, "Failed to connect to container %s: %m", *i); continue; } @@ -1248,18 +1248,33 @@ static int compare_unit_file_list(const void *a, const void *b) { } static bool output_show_unit_file(const UnitFileList *u, char **patterns) { - const char *dot; - if (!strv_isempty(patterns)) { char **pattern; STRV_FOREACH(pattern, patterns) if (fnmatch(*pattern, basename(u->path), FNM_NOESCAPE) == 0) - return true; + goto next; return false; } - return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1)); +next: + if (!strv_isempty(arg_types)) { + const char *dot; + + dot = strrchr(u->path, '.'); + if (!dot) + return false; + + if (!strv_find(arg_types, dot+1)) + return false; + } + + if (!strv_isempty(arg_states)) { + if (!strv_find(arg_states, unit_file_state_to_string(u->state))) + return false; + } + + return true; } static void output_unit_file_list(const UnitFileList *units, unsigned c) { @@ -1338,24 +1353,21 @@ static int list_unit_files(sd_bus *bus, char **args) { Iterator i; unsigned n_units; - h = hashmap_new(string_hash_func, string_compare_func); + h = hashmap_new(&string_hash_ops); if (!h) return log_oom(); r = unit_file_get_list(arg_scope, arg_root, h); if (r < 0) { unit_file_list_free(h); - log_error("Failed to get unit file list: %s", strerror(-r)); + log_error_errno(r, "Failed to get unit file list: %m"); return r; } n_units = hashmap_size(h); - if (n_units == 0) - return 0; - units = new(UnitFileList, n_units); - if (!units) { + if (!units && n_units > 0) { unit_file_list_free(h); return log_oom(); } @@ -1411,14 +1423,13 @@ static int list_unit_files(sd_bus *bus, char **args) { return bus_log_parse_error(r); } - if (c > 0) { - qsort(units, c, sizeof(UnitFileList), compare_unit_file_list); - output_unit_file_list(units, c); - } + qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list); + output_unit_file_list(units, c); - if (avoid_bus()) + if (avoid_bus()) { for (unit = units; unit < units + c; unit++) free(unit->path); + } return 0; } @@ -1469,11 +1480,13 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha "RequiresOverridable\0" "Requisite\0" "RequisiteOverridable\0" - "Wants\0", + "Wants\0" + "BindsTo\0", [DEPENDENCY_REVERSE] = "RequiredBy\0" "RequiredByOverridable\0" "WantedBy\0" - "PartOf\0", + "PartOf\0" + "BoundBy\0", [DEPENDENCY_AFTER] = "After\0", [DEPENDENCY_BEFORE] = "Before\0", }; @@ -1893,10 +1906,8 @@ static int get_default(sd_bus *bus, char **args) { if (!bus || avoid_bus()) { r = unit_file_get_default(arg_scope, arg_root, &_path); - if (r < 0) { - log_error("Failed to get default target: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get default target: %m"); path = _path; } else { @@ -1976,28 +1987,36 @@ static int set_default(sd_bus *bus, char **args) { if (!bus || avoid_bus()) { r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); - if (r < 0) { - log_error("Failed to set default target: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to set default target: %m"); if (!arg_quiet) dump_unit_file_changes(changes, n_changes); r = 0; } else { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "SetDefaultTarget", - &error, - &reply, - "sb", unit, true); + "SetDefaultTarget"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "sb", unit, 1); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to set default target: %s", bus_error_message(&error, -r)); return r; @@ -2164,6 +2183,7 @@ static int list_jobs(sd_bus *bus, char **args) { static int cancel_job(sd_bus *bus, char **args) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; char **name; + int r = 0; assert(args); @@ -2171,31 +2191,41 @@ static int cancel_job(sd_bus *bus, char **args) { return daemon_reload(bus, args); STRV_FOREACH(name, args+1) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; uint32_t id; - int r; + int q; - r = safe_atou32(*name, &id); - if (r < 0) { - log_error("Failed to parse job id \"%s\": %s", *name, strerror(-r)); - return r; - } + q = safe_atou32(*name, &id); + if (q < 0) + return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name); - r = sd_bus_call_method( + q = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "CancelJob", - &error, - NULL, - "u", id); - if (r < 0) { - log_error("Failed to cancel job %u: %s", (unsigned) id, bus_error_message(&error, r)); - return r; + "CancelJob"); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (q < 0) + return bus_log_create_error(1); + + q = sd_bus_message_append(m, "u", id); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_call(bus, m, 0, &error, NULL); + if (q < 0) { + log_error("Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q)); + if (r == 0) + r = q; } } - return 0; + return r; } static int need_daemon_reload(sd_bus *bus, const char *unit) { @@ -2354,9 +2384,19 @@ static int check_wait_response(WaitData *d) { else if (streq(d->result, "canceled")) log_error("Job for %s canceled.", strna(d->name)); else if (streq(d->result, "dependency")) - log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d->name)); - else if (!streq(d->result, "done") && !streq(d->result, "skipped")) - log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d->name), strna(d->name)); + log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name)); + else if (!streq(d->result, "done") && !streq(d->result, "skipped")) { + if (d->name) { + bool quotes; + + quotes = chars_intersect(d->name, SHELL_NEED_QUOTES); + + log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.", + d->name, + quotes ? "'" : "", d->name, quotes ? "'" : ""); + } else + log_error("Job failed. See \"journalctl -xe\" for details."); + } } if (streq(d->result, "timeout")) @@ -2385,10 +2425,8 @@ static int wait_for_jobs(sd_bus *bus, Set *s) { while (!set_isempty(s)) { q = bus_process_wait(bus); - if (q < 0) { - log_error("Failed to wait for response: %s", strerror(-r)); - return q; - } + if (q < 0) + return log_error_errno(q, "Failed to wait for response: %m"); if (d.result) { q = check_wait_response(&d); @@ -2514,10 +2552,8 @@ static int check_triggering_units( STRV_FOREACH(i, triggered_by) { r = check_one_unit(bus, *i, "active\0reloading\0", true); - if (r < 0) { - log_error("Failed to check unit: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to check unit: %m"); if (r == 0) continue; @@ -2533,6 +2569,23 @@ static int check_triggering_units( return 0; } +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 const char *verb_to_method(const char *verb) { uint i; @@ -2561,7 +2614,7 @@ static int start_unit_one( sd_bus_error *error, Set *s) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; const char *path; int r; @@ -2571,15 +2624,26 @@ static int start_unit_one( assert(error); log_debug("Calling manager for %s on %s, %s", method, name, mode); - r = sd_bus_call_method( + + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - method, - error, - &reply, - "ss", name, mode); + method); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "ss", name, mode); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, error, &reply); if (r < 0) { const char *verb; @@ -2698,7 +2762,7 @@ static enum action verb_to_action(const char *verb) { static int start_unit(sd_bus *bus, char **args) { _cleanup_set_free_free_ Set *s = NULL; _cleanup_strv_free_ char **names = NULL; - const char *method, *mode, *one_name; + const char *method, *mode, *one_name, *suffix = NULL; char **name; int r = 0; @@ -2711,8 +2775,11 @@ static int start_unit(sd_bus *bus, char **args) { method = verb_to_method(args[0]); action = verb_to_action(args[0]); - mode = streq(args[0], "isolate") ? "isolate" : - action_table[action].mode ?: arg_job_mode; + if (streq(args[0], "isolate")) { + mode = "isolate"; + suffix = ".target"; + } else + mode = action_table[action].mode ?: arg_job_mode; one_name = action_table[action].target; } else { @@ -2728,19 +2795,17 @@ static int start_unit(sd_bus *bus, char **args) { if (one_name) names = strv_new(one_name, NULL); else { - r = expand_names(bus, args + 1, NULL, &names); + r = expand_names(bus, args + 1, suffix, &names); if (r < 0) - log_error("Failed to expand names: %s", strerror(-r)); + log_error_errno(r, "Failed to expand names: %m"); } if (!arg_no_block) { r = enable_wait_for_jobs(bus); - if (r < 0) { - log_error("Could not watch jobs: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Could not watch jobs: %m"); - s = set_new(string_hash_func, string_compare_func); + s = set_new(&string_hash_ops); if (!s) return log_oom(); } @@ -2818,7 +2883,7 @@ static int reboot_with_logind(sd_bus *bus, enum action a) { method, &error, NULL, - "b", true); + "b", arg_ask_password); if (r < 0) log_error("Failed to execute operation: %s", bus_error_message(&error, r)); @@ -2997,10 +3062,8 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch assert(args); r = expand_names(bus, args, NULL, &names); - if (r < 0) { - log_error("Failed to expand names: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { int state; @@ -3038,21 +3101,32 @@ static int kill_unit(sd_bus *bus, char **args) { r = expand_names(bus, args + 1, NULL, &names); if (r < 0) - log_error("Failed to expand names: %s", strerror(-r)); + log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - q = sd_bus_call_method( + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + + q = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "KillUnit", - &error, - NULL, - "ssi", *names, arg_kill_who, arg_signal); + "KillUnit"); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_message_append(m, "ssi", *names, arg_kill_who, arg_signal); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_call(bus, m, 0, &error, NULL); if (q < 0) { - log_error("Failed to kill unit %s: %s", - *names, bus_error_message(&error, r)); + log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q)); if (r == 0) r = q; } @@ -3186,7 +3260,14 @@ typedef struct UnitStatusInfo { bool failed_condition_trigger; bool failed_condition_negate; const char *failed_condition; - const char *failed_condition_param; + const char *failed_condition_parameter; + + usec_t assert_timestamp; + bool assert_result; + bool failed_assert_trigger; + bool failed_assert_negate; + const char *failed_assert; + const char *failed_assert_parameter; /* Socket */ unsigned n_accepted; @@ -3330,7 +3411,8 @@ static void print_status_info( s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp); s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); - printf(" start condition failed at %s%s%s\n", + printf("Condition: start %scondition failed%s at %s%s%s\n", + ansi_highlight_yellow(), ansi_highlight_off(), s2, s1 ? "; " : "", s1 ? s1 : ""); if (i->failed_condition_trigger) printf(" none of the trigger conditions were met\n"); @@ -3338,7 +3420,23 @@ static void print_status_info( printf(" %s=%s%s was not met\n", i->failed_condition, i->failed_condition_negate ? "!" : "", - i->failed_condition_param); + i->failed_condition_parameter); + } + + if (!i->assert_result && i->assert_timestamp > 0) { + s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp); + s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp); + + printf(" Assert: start %sassertion failed%s at %s%s%s\n", + ansi_highlight_red(), ansi_highlight_off(), + s2, s1 ? "; " : "", s1 ? s1 : ""); + if (i->failed_assert_trigger) + printf(" none of the trigger assertions were met\n"); + else if (i->failed_assert) + printf(" %s=%s%s was not met\n", + i->failed_assert, + i->failed_assert_negate ? "!" : "", + i->failed_assert_parameter); } if (i->sysfs_path) @@ -3403,7 +3501,7 @@ static void print_status_info( if (i->main_pid > 0 || i->control_pid > 0) { if (i->main_pid > 0) { - printf(" Main PID: %u", (unsigned) i->main_pid); + printf(" Main PID: "PID_FMT, i->main_pid); if (i->running) { _cleanup_free_ char *comm = NULL; @@ -3434,7 +3532,7 @@ static void print_status_info( if (i->control_pid > 0) { _cleanup_free_ char *c = NULL; - printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid); + printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid); get_process_comm(i->control_pid, &c); if (c) @@ -3589,6 +3687,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * i->need_daemon_reload = b; else if (streq(name, "ConditionResult")) i->condition_result = b; + else if (streq(name, "AssertResult")) + i->assert_result = b; break; } @@ -3658,6 +3758,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * i->active_exit_timestamp = (usec_t) u; else if (streq(name, "ConditionTimestamp")) i->condition_timestamp = (usec_t) u; + else if (streq(name, "AssertTimestamp")) + i->assert_timestamp = (usec_t) u; break; } @@ -3750,7 +3852,32 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * i->failed_condition = cond; i->failed_condition_trigger = trigger; i->failed_condition_negate = negate; - i->failed_condition_param = param; + i->failed_condition_parameter = param; + } + } + 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); + + } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Asserts")) { + const char *cond, *param; + int trigger, negate; + int32_t state; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, ¶m, &state)) > 0) { + log_debug("%s %d %d %s %d", cond, trigger, negate, param, state); + if (state < 0 && (!trigger || !i->failed_assert)) { + i->failed_assert = cond; + i->failed_assert_trigger = trigger; + i->failed_assert_negate = negate; + i->failed_assert_parameter = param; } } if (r < 0) @@ -3822,7 +3949,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte return bus_log_parse_error(r); if (u > 0) - printf("%s=%u\n", name, (unsigned) u); + printf("%s=%"PRIu32"\n", name, u); else if (arg_all) printf("%s=\n", name); @@ -3993,14 +4120,14 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte tt = strv_join(info.argv, " "); - printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n", + printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }\n", name, strna(info.path), strna(tt), yes_no(info.ignore), strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)), strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)), - (unsigned) info. pid, + info.pid, sigchld_code_to_string(info.code), info.status, info.code == CLD_EXITED ? "" : "/", @@ -4297,10 +4424,8 @@ static int show_system_status(sd_bus *bus) { return log_oom(); r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi); - if (r < 0) { - log_error("Failed to read server status: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to read server status: %m"); if (streq_ptr(mi.state, "degraded")) { on = ansi_highlight_red(); @@ -4417,7 +4542,7 @@ static int show(sd_bus *bus, char **args) { r = expand_names(bus, patterns, NULL, &names); if (r < 0) - log_error("Failed to expand names: %s", strerror(-r)); + log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { _cleanup_free_ char *unit; @@ -4443,7 +4568,6 @@ static int show(sd_bus *bus, char **args) { } static int cat(sd_bus *bus, char **args) { - _cleanup_free_ char *unit = NULL; _cleanup_strv_free_ char **names = NULL; char **name; bool first = true; @@ -4454,14 +4578,14 @@ static int cat(sd_bus *bus, char **args) { r = expand_names(bus, args + 1, NULL, &names); if (r < 0) - log_error("Failed to expand names: %s", strerror(-r)); + log_error_errno(r, "Failed to expand names: %m"); pager_open_if_enabled(); STRV_FOREACH(name, names) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_strv_free_ char **dropin_paths = NULL; - _cleanup_free_ char *fragment_path = NULL; + _cleanup_free_ char *fragment_path = NULL, *unit = NULL; char **path; unit = unit_dbus_path_from_name(*name); @@ -4510,9 +4634,9 @@ static int cat(sd_bus *bus, char **args) { ansi_highlight_off()); fflush(stdout); - r = sendfile_full(STDOUT_FILENO, fragment_path); + r = copy_file_fd(fragment_path, STDOUT_FILENO); if (r < 0) { - log_warning("Failed to cat %s: %s", fragment_path, strerror(-r)); + log_warning_errno(r, "Failed to cat %s: %m", fragment_path); continue; } } @@ -4525,9 +4649,9 @@ static int cat(sd_bus *bus, char **args) { ansi_highlight_off()); fflush(stdout); - r = sendfile_full(STDOUT_FILENO, *path); + r = copy_file_fd(*path, STDOUT_FILENO); if (r < 0) { - log_warning("Failed to cat %s: %s", *path, strerror(-r)); + log_warning_errno(r, "Failed to cat %s: %m", *path); continue; } } @@ -4553,6 +4677,10 @@ static int set_property(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + n = unit_name_mangle(args[1], MANGLE_NOGLOB); if (!n) return log_oom(); @@ -4594,7 +4722,7 @@ static int set_property(sd_bus *bus, char **args) { static int snapshot(sd_bus *bus, char **args) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; _cleanup_free_ char *n = NULL, *id = NULL; const char *path; int r; @@ -4606,15 +4734,25 @@ static int snapshot(sd_bus *bus, char **args) { if (!n) return log_oom(); - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "CreateSnapshot", - &error, - &reply, - "sb", n, false); + "CreateSnapshot"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "sb", n, false); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to create snapshot: %s", bus_error_message(&error, r)); return r; @@ -4647,27 +4785,39 @@ static int delete_snapshot(sd_bus *bus, char **args) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_strv_free_ char **names = NULL; char **name; - int r, q; + int r; assert(args); r = expand_names(bus, args + 1, ".snapshot", &names); if (r < 0) - log_error("Failed to expand names: %s", strerror(-r)); + log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - q = sd_bus_call_method( + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int q; + + q = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "RemoveSnapshot", - &error, - NULL, - "s", *name); + "RemoveSnapshot"); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_message_append(m, "s", *name); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_call(bus, m, 0, &error, NULL); if (q < 0) { - log_error("Failed to remove snapshot %s: %s", - *name, bus_error_message(&error, r)); + log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q)); if (r == 0) r = q; } @@ -4678,6 +4828,7 @@ static int delete_snapshot(sd_bus *bus, char **args) { static int daemon_reload(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; const char *method; int r; @@ -4701,16 +4852,21 @@ static int daemon_reload(sd_bus *bus, char **args) { /* "daemon-reload" */ "Reload"; } - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - method, - &error, - NULL, - NULL); + method); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + r = sd_bus_call(bus, m, 0, &error, NULL); if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL) /* There's always a fallback possible for * legacy actions. */ @@ -4736,21 +4892,32 @@ static int reset_failed(sd_bus *bus, char **args) { r = expand_names(bus, args + 1, NULL, &names); if (r < 0) - log_error("Failed to expand names: %s", strerror(-r)); + log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - q = sd_bus_call_method( + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + + q = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "ResetFailedUnit", - &error, - NULL, - "s", *name); + "ResetFailedUnit"); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_message_append(m, "s", *name); + if (q < 0) + return bus_log_create_error(q); + + q = sd_bus_call(bus, m, 0, &error, NULL); if (q < 0) { - log_error("Failed to reset failed state of unit %s: %s", - *name, bus_error_message(&error, r)); + log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q)); if (r == 0) r = q; } @@ -4819,7 +4986,7 @@ static int switch_root(sd_bus *bus, char **args) { "init", &cmdline_init, NULL); if (r < 0) - log_debug("Failed to parse /proc/cmdline: %s", strerror(-r)); + log_debug_errno(r, "Failed to parse /proc/cmdline: %m"); init = cmdline_init; } @@ -4881,6 +5048,10 @@ static int set_environment(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + r = sd_bus_message_append_strv(m, args + 1); if (r < 0) return bus_log_create_error(r); @@ -4912,6 +5083,10 @@ static int import_environment(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + if (strv_isempty(args + 1)) r = sd_bus_message_append_strv(m, environ); else { @@ -5045,7 +5220,7 @@ static int enable_sysv_units(const char *verb, char **args) { pid = fork(); if (pid < 0) { - log_error("Failed to fork: %m"); + log_error_errno(errno, "Failed to fork: %m"); return -errno; } else if (pid == 0) { /* Child */ @@ -5056,7 +5231,7 @@ static int enable_sysv_units(const char *verb, char **args) { j = wait_for_terminate(pid, &status); if (j < 0) { - log_error("Failed to wait for child: %s", strerror(-r)); + log_error_errno(r, "Failed to wait for child: %m"); return j; } @@ -5170,7 +5345,7 @@ static int enable_unit(sd_bus *bus, char **args) { assert_not_reached("Unknown verb"); if (r < 0) { - log_error("Operation failed: %s", strerror(-r)); + log_error_errno(r, "Operation failed: %m"); goto finish; } @@ -5223,6 +5398,10 @@ static int enable_unit(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + r = sd_bus_message_append_strv(m, names); if (r < 0) return bus_log_create_error(r); @@ -5283,6 +5462,90 @@ finish: return r; } +static int add_dependency(sd_bus *bus, char **args) { + _cleanup_strv_free_ char **names = NULL; + _cleanup_free_ char *target = NULL; + const char *verb = args[0]; + UnitDependency dep; + int r = 0; + + if (!args[1]) + return 0; + + target = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target"); + if (!target) + return log_oom(); + + r = mangle_names(args+2, &names); + if (r < 0) + return r; + + if (streq(verb, "add-wants")) + dep = UNIT_WANTS; + else if (streq(verb, "add-requires")) + dep = UNIT_REQUIRES; + else + assert_not_reached("Unknown verb"); + + if (!bus || avoid_bus()) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + + r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); + + if (r < 0) + return log_error_errno(r, "Can't add dependency: %m"); + + if (!arg_quiet) + dump_unit_file_changes(changes, n_changes); + + unit_file_changes_free(changes, n_changes); + + } else { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + + r = sd_bus_message_new_method_call( + bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "AddDependencyUnitFiles"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, names); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, &reply); + if (r < 0) { + log_error("Failed to execute operation: %s", bus_error_message(&error, r)); + return r; + } + + r = deserialize_and_dump_unit_file_changes(reply); + if (r < 0) + return r; + + if (!arg_no_reload) + r = daemon_reload(bus, args); + else + r = 0; + } + + return r; +} + static int preset_all(sd_bus *bus, char **args) { UnitFileChange *changes = NULL; unsigned n_changes = 0; @@ -5292,7 +5555,7 @@ static int preset_all(sd_bus *bus, char **args) { r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); if (r < 0) { - log_error("Operation failed: %s", strerror(-r)); + log_error_errno(r, "Operation failed: %m"); goto finish; } @@ -5302,21 +5565,33 @@ static int preset_all(sd_bus *bus, char **args) { r = 0; } else { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "PresetAllUnitFiles", - &error, - &reply, + "PresetAllUnitFiles"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append( + m, "sbb", unit_file_preset_mode_to_string(arg_preset_mode), arg_runtime, arg_force); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to execute operation: %s", bus_error_message(&error, r)); return r; @@ -5362,14 +5637,13 @@ static int unit_is_enabled(sd_bus *bus, char **args) { UnitFileState state; state = unit_file_get_state(arg_scope, arg_root, *name); - if (state < 0) { - log_error("Failed to get unit file state for %s: %s", *name, strerror(-state)); - return state; - } + if (state < 0) + return log_error_errno(state, "Failed to get unit file state for %s: %m", *name); if (state == UNIT_FILE_ENABLED || state == UNIT_FILE_ENABLED_RUNTIME || - state == UNIT_FILE_STATIC) + state == UNIT_FILE_STATIC || + state == UNIT_FILE_INDIRECT) enabled = true; if (!arg_quiet) @@ -5399,9 +5673,7 @@ static int unit_is_enabled(sd_bus *bus, char **args) { if (r < 0) return bus_log_parse_error(r); - if (streq(s, "enabled") || - streq(s, "enabled-runtime") || - streq(s, "static")) + if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect")) enabled = true; if (!arg_quiet) @@ -5528,6 +5800,10 @@ static void systemctl_help(void) { " unmask NAME... Unmask one or more units\n" " link PATH... Link one or more units files into\n" " the search path\n" + " add-wants TARGET NAME... Add 'Wants' dependency for the target\n" + " on specified one or more units\n" + " add-requires TARGET NAME... Add 'Requires' dependency for the target\n" + " on specified one or more units\n" " get-default Get the name of the default target\n" " set-default NAME Set the default target\n\n" "Machine Commands:\n" @@ -6445,14 +6721,14 @@ static int talk_initctl(void) { if (errno == ENOENT) return 0; - log_error("Failed to open "INIT_FIFO": %m"); + log_error_errno(errno, "Failed to open "INIT_FIFO": %m"); return -errno; } errno = 0; r = loop_write(fd, &request, sizeof(request), false) != sizeof(request); if (r) { - log_error("Failed to write to "INIT_FIFO": %m"); + log_error_errno(errno, "Failed to write to "INIT_FIFO": %m"); return errno > 0 ? -errno : -EIO; } @@ -6538,6 +6814,8 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) { { "get-default", EQUAL, 1, get_default, NOBUS }, { "set-property", MORE, 3, set_property }, { "is-system-running", EQUAL, 1, is_system_running }, + { "add-wants", MORE, 3, add_dependency, NOBUS }, + { "add-requires", MORE, 3, add_dependency, NOBUS }, {} }, *verb = verbs; @@ -6599,7 +6877,7 @@ found: * enable/disable */ if (verb->bus == NOBUS) { if (!bus && !avoid_bus()) { - log_error("Failed to get D-Bus connection: %s", strerror(-bus_error)); + log_error_errno(bus_error, "Failed to get D-Bus connection: %m"); return -EIO; } @@ -6610,7 +6888,7 @@ found: } if ((verb->bus != FORCE || arg_force <= 0) && !bus) { - log_error("Failed to get D-Bus connection: %s", strerror(-bus_error)); + log_error_errno(bus_error, "Failed to get D-Bus connection: %m"); return -EIO; } } @@ -6675,7 +6953,7 @@ static int reload_with_fallback(sd_bus *bus) { assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC); if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) { - log_error("kill() failed: %m"); + log_error_errno(errno, "kill() failed: %m"); return -errno; } @@ -6705,8 +6983,13 @@ done: static int halt_now(enum action a) { -/* Make sure C-A-D is handled by the kernel from this - * point on... */ + /* The kernel will automaticall flush ATA disks and suchlike + * on reboot(), but the file systems need to be synce'd + * explicitly in advance. */ + sync(); + + /* Make sure C-A-D is handled by the kernel from this point + * on... */ reboot(RB_ENABLE_CAD); switch (a) { @@ -6783,7 +7066,7 @@ static int halt_main(sd_bus *bus) { m); if (r < 0) - log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r)); + log_warning_errno(r, "Failed to talk to shutdownd, proceeding with immediate shutdown: %m"); else { char date[FORMAT_TIMESTAMP_MAX]; @@ -6802,7 +7085,7 @@ static int halt_main(sd_bus *bus) { else { r = utmp_put_shutdown(); if (r < 0) - log_warning("Failed to write utmp record: %s", strerror(-r)); + log_warning_errno(r, "Failed to write utmp record: %m"); } } @@ -6810,7 +7093,7 @@ static int halt_main(sd_bus *bus) { return 0; r = halt_now(arg_action); - log_error("Failed to reboot: %s", strerror(-r)); + log_error_errno(r, "Failed to reboot: %m"); return r; } @@ -6908,7 +7191,7 @@ int main(int argc, char*argv[]) { 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)); + log_warning_errno(r, "Failed to talk to shutdownd, shutdown hasn't been cancelled: %m"); break; }