diff options
Diffstat (limited to 'src/analyze/analyze.c')
-rw-r--r-- | src/analyze/analyze.c | 516 |
1 files changed, 317 insertions, 199 deletions
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index c0863e4167..cbf9354a7a 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,25 +18,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> #include <getopt.h> #include <locale.h> +#include <stdio.h> +#include <stdlib.h> #include "sd-bus.h" -#include "bus-util.h" + +#include "alloc-util.h" +#include "analyze-verify.h" #include "bus-error.h" -#include "log.h" -#include "build.h" -#include "util.h" -#include "strxcpyx.h" -#include "strv.h" -#include "unit-name.h" -#include "special.h" +#include "bus-unit-util.h" +#include "bus-util.h" +#include "glob-util.h" #include "hashmap.h" +#include "locale-util.h" +#include "log.h" #include "pager.h" -#include "analyze-verify.h" +#include "parse-util.h" +#include "special.h" +#include "strv.h" +#include "strxcpyx.h" #include "terminal-util.h" +#include "unit-name.h" +#include "util.h" #define SCALE_X (0.1 / 1000.0) /* pixels per us */ #define SCALE_Y (20.0) @@ -58,7 +61,7 @@ svg(" <text class=\"%s\" x=\"%.03f\" y=\"%.03f\">", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \ svg(format, ## __VA_ARGS__); \ svg("</text>\n"); \ - } while(false) + } while (false) static enum dot { DEP_ALL, @@ -88,6 +91,18 @@ struct boot_times { usec_t generators_finish_time; usec_t unitsload_start_time; usec_t unitsload_finish_time; + + /* + * If we're analyzing the user instance, all timestamps will be offset + * by its own start-up timestamp, which may be arbitrarily big. + * With "plot", this causes arbitrarily wide output SVG files which almost + * completely consist of empty space. Thus we cancel out this offset. + * + * This offset is subtracted from times above by acquire_boot_times(), + * but it still needs to be subtracted from unit-specific timestamps + * (so it is stored here for reference). + */ + usec_t reverse_offset; }; struct unit_times { @@ -109,16 +124,8 @@ struct host_info { char *architecture; }; -static void pager_open_if_enabled(void) { - - if (arg_no_pager) - return; - - pager_open(false); -} - static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -145,7 +152,7 @@ static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *in } static int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -188,95 +195,13 @@ static void free_unit_times(struct unit_times *t, unsigned n) { free(t); } -static int acquire_time_data(sd_bus *bus, struct unit_times **out) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - int r, c = 0; - struct unit_times *unit_times = NULL; - size_t size = 0; - UnitInfo u; - - r = sd_bus_call_method( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "ListUnits", - &error, &reply, - NULL); - if (r < 0) { - log_error("Failed to list units: %s", bus_error_message(&error, -r)); - goto fail; - } +static void subtract_timestamp(usec_t *a, usec_t b) { + assert(a); - r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)"); - if (r < 0) { - bus_log_parse_error(r); - goto fail; + if (*a > 0) { + assert(*a >= b); + *a -= b; } - - while ((r = bus_parse_unit_info(reply, &u)) > 0) { - struct unit_times *t; - - if (!GREEDY_REALLOC(unit_times, size, c+1)) { - r = log_oom(); - goto fail; - } - - t = unit_times+c; - t->name = NULL; - - assert_cc(sizeof(usec_t) == sizeof(uint64_t)); - - if (bus_get_uint64_property(bus, u.unit_path, - "org.freedesktop.systemd1.Unit", - "InactiveExitTimestampMonotonic", - &t->activating) < 0 || - bus_get_uint64_property(bus, u.unit_path, - "org.freedesktop.systemd1.Unit", - "ActiveEnterTimestampMonotonic", - &t->activated) < 0 || - bus_get_uint64_property(bus, u.unit_path, - "org.freedesktop.systemd1.Unit", - "ActiveExitTimestampMonotonic", - &t->deactivating) < 0 || - bus_get_uint64_property(bus, u.unit_path, - "org.freedesktop.systemd1.Unit", - "InactiveEnterTimestampMonotonic", - &t->deactivated) < 0) { - r = -EIO; - goto fail; - } - - if (t->activated >= t->activating) - t->time = t->activated - t->activating; - else if (t->deactivated >= t->activating) - t->time = t->deactivated - t->activating; - else - t->time = 0; - - if (t->activating == 0) - continue; - - t->name = strdup(u.id); - if (t->name == NULL) { - r = log_oom(); - goto fail; - } - c++; - } - if (r < 0) { - bus_log_parse_error(r); - goto fail; - } - - *out = unit_times; - return c; - -fail: - if (unit_times) - free_unit_times(unit_times, (unsigned) c); - return r; } static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) { @@ -355,10 +280,30 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) { return -EINPROGRESS; } - if (times.initrd_time) - times.kernel_done_time = times.initrd_time; - else - times.kernel_done_time = times.userspace_time; + if (arg_user) { + /* + * User-instance-specific timestamps processing + * (see comment to reverse_offset in struct boot_times). + */ + times.reverse_offset = times.userspace_time; + + times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time = times.userspace_time = 0; + subtract_timestamp(×.finish_time, times.reverse_offset); + + subtract_timestamp(×.security_start_time, times.reverse_offset); + subtract_timestamp(×.security_finish_time, times.reverse_offset); + + subtract_timestamp(×.generators_start_time, times.reverse_offset); + subtract_timestamp(×.generators_finish_time, times.reverse_offset); + + subtract_timestamp(×.unitsload_start_time, times.reverse_offset); + subtract_timestamp(×.unitsload_finish_time, times.reverse_offset); + } else { + if (times.initrd_time) + times.kernel_done_time = times.initrd_time; + else + times.kernel_done_time = times.userspace_time; + } cached = true; @@ -368,6 +313,10 @@ finish: } static void free_host_info(struct host_info *hi) { + + if (!hi) + return; + free(hi->hostname); free(hi->kernel_name); free(hi->kernel_release); @@ -378,25 +327,129 @@ static void free_host_info(struct host_info *hi) { free(hi); } -static int acquire_host_info(sd_bus *bus, struct host_info **hi) { - int r; - struct host_info *host; +DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info*, free_host_info); +static int acquire_time_data(sd_bus *bus, struct unit_times **out) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r, c = 0; + struct boot_times *boot_times = NULL; + struct unit_times *unit_times = NULL; + size_t size = 0; + UnitInfo u; + + r = acquire_boot_times(bus, &boot_times); + if (r < 0) + goto fail; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnits", + &error, &reply, + NULL); + if (r < 0) { + log_error("Failed to list units: %s", bus_error_message(&error, -r)); + goto fail; + } + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)"); + if (r < 0) { + bus_log_parse_error(r); + goto fail; + } + + while ((r = bus_parse_unit_info(reply, &u)) > 0) { + struct unit_times *t; + + if (!GREEDY_REALLOC(unit_times, size, c+1)) { + r = log_oom(); + goto fail; + } + + t = unit_times+c; + t->name = NULL; + + assert_cc(sizeof(usec_t) == sizeof(uint64_t)); + + if (bus_get_uint64_property(bus, u.unit_path, + "org.freedesktop.systemd1.Unit", + "InactiveExitTimestampMonotonic", + &t->activating) < 0 || + bus_get_uint64_property(bus, u.unit_path, + "org.freedesktop.systemd1.Unit", + "ActiveEnterTimestampMonotonic", + &t->activated) < 0 || + bus_get_uint64_property(bus, u.unit_path, + "org.freedesktop.systemd1.Unit", + "ActiveExitTimestampMonotonic", + &t->deactivating) < 0 || + bus_get_uint64_property(bus, u.unit_path, + "org.freedesktop.systemd1.Unit", + "InactiveEnterTimestampMonotonic", + &t->deactivated) < 0) { + r = -EIO; + goto fail; + } + + subtract_timestamp(&t->activating, boot_times->reverse_offset); + subtract_timestamp(&t->activated, boot_times->reverse_offset); + subtract_timestamp(&t->deactivating, boot_times->reverse_offset); + subtract_timestamp(&t->deactivated, boot_times->reverse_offset); + + if (t->activated >= t->activating) + t->time = t->activated - t->activating; + else if (t->deactivated >= t->activating) + t->time = t->deactivated - t->activating; + else + t->time = 0; + + if (t->activating == 0) + continue; + + t->name = strdup(u.id); + if (t->name == NULL) { + r = log_oom(); + goto fail; + } + c++; + } + if (r < 0) { + bus_log_parse_error(r); + goto fail; + } + + *out = unit_times; + return c; + +fail: + if (unit_times) + free_unit_times(unit_times, (unsigned) c); + return r; +} + +static int acquire_host_info(sd_bus *bus, struct host_info **hi) { static const struct bus_properties_map hostname_map[] = { - { "Hostname", "s", NULL, offsetof(struct host_info, hostname) }, - { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) }, - { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) }, - { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) }, + { "Hostname", "s", NULL, offsetof(struct host_info, hostname) }, + { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) }, + { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) }, + { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) }, { "OperatingSystemPrettyName", "s", NULL, offsetof(struct host_info, os_pretty_name) }, {} }; static const struct bus_properties_map manager_map[] = { - { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) }, - { "Architecture", "s", NULL, offsetof(struct host_info, architecture) }, + { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) }, + { "Architecture", "s", NULL, offsetof(struct host_info, architecture) }, {} }; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(free_host_infop) struct host_info *host; + int r; + host = new0(struct host_info, 1); if (!host) return log_oom(); @@ -407,7 +460,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) { hostname_map, host); if (r < 0) - goto fail; + log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r)); r = bus_map_all_properties(bus, "org.freedesktop.systemd1", @@ -415,13 +468,12 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) { manager_map, host); if (r < 0) - goto fail; + return log_error_errno(r, "Failed to get host information from systemd: %s", bus_error_message(&error, r)); *hi = host; + host = NULL; + return 0; -fail: - free_host_info(host); - return r; } static int pretty_boot_time(sd_bus *bus, char **_buf) { @@ -450,10 +502,7 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) { size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC)); size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC)); - if (t->kernel_time > 0) - strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC)); - else - strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC)); + strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC)); ptr = strdup(buf); if (!ptr) @@ -487,9 +536,9 @@ static void svg_graph_box(double height, double begin, double end) { } static int analyze_plot(sd_bus *bus) { + _cleanup_(free_host_infop) struct host_info *host = NULL; struct unit_times *times; struct boot_times *boot; - struct host_info *host = NULL; int n, m = 1, y=0; double width; _cleanup_free_ char *pretty_times = NULL; @@ -509,7 +558,7 @@ static int analyze_plot(sd_bus *bus) { n = acquire_time_data(bus, ×); if (n <= 0) - goto out; + return n; qsort(times, n, sizeof(struct unit_times), compare_unit_start); @@ -534,8 +583,7 @@ static int analyze_plot(sd_bus *bus) { if (u->activating < boot->userspace_time || u->activating > boot->finish_time) { - free(u->name); - u->name = NULL; + u->name = mfree(u->name); continue; } @@ -606,12 +654,12 @@ static int analyze_plot(sd_bus *bus) { svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times); svg("<text x=\"20\" y=\"30\">%s %s (%s %s %s) %s %s</text>", isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name, - isempty(host->hostname) ? "" : host->hostname, - isempty(host->kernel_name) ? "" : host->kernel_name, - isempty(host->kernel_release) ? "" : host->kernel_release, - isempty(host->kernel_version) ? "" : host->kernel_version, - isempty(host->architecture) ? "" : host->architecture, - isempty(host->virtualization) ? "" : host->virtualization); + strempty(host->hostname), + strempty(host->kernel_name), + strempty(host->kernel_release), + strempty(host->kernel_version), + strempty(host->architecture), + strempty(host->virtualization)); svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time)); svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time); @@ -695,8 +743,6 @@ static int analyze_plot(sd_bus *bus) { free_unit_times(times, (unsigned) n); n = 0; -out: - free_host_info(host); return n; } @@ -706,15 +752,15 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX]; for (i = level; i != 0; i--) - printf("%s", draw_special_char(branches & (1 << (i-1)) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE)); + printf("%s", special_glyph(branches & (1 << (i-1)) ? TREE_VERTICAL : TREE_SPACE)); - printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); + printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH)); if (times) { if (times->time) - printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED_ON, name, + printf("%s%s @%s +%s%s", ansi_highlight_red(), name, format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC), - format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF); + format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ansi_normal()); else if (times->activated > boot->userspace_time) printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC)); else @@ -797,11 +843,8 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev STRV_FOREACH(c, deps) { times = hashmap_get(unit_times_hashmap, *c); - if (times && times->activated - && times->activated <= boot->finish_time - && (service_longest - times->activated) <= arg_fuzz) { + if (times && times->activated && times->activated <= boot->finish_time && (service_longest - times->activated) <= arg_fuzz) to_print++; - } } if (!to_print) @@ -847,8 +890,8 @@ static int list_dependencies(sd_bus *bus, const char *name) { int r; const char *id; _cleanup_free_ char *path = NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; struct boot_times *boot; assert(bus); @@ -883,8 +926,8 @@ static int list_dependencies(sd_bus *bus, const char *name) { if (times) { if (times->time) - printf("%s%s +%s%s\n", ANSI_HIGHLIGHT_RED_ON, id, - format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF); + printf("%s%s +%s%s\n", ansi_highlight_red(), id, + format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ansi_normal()); else if (times->activated > boot->userspace_time) printf("%s @%s\n", id, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC)); else @@ -915,7 +958,7 @@ static int analyze_critical_chain(sd_bus *bus, char *names[]) { } unit_times_hashmap = h; - pager_open_if_enabled(); + pager_open(arg_no_pager, false); puts("The time after the unit is active or started is printed after the \"@\" character.\n" "The time the unit takes to start is printed after the \"+\" character.\n"); @@ -943,7 +986,7 @@ static int analyze_blame(sd_bus *bus) { qsort(times, n, sizeof(struct unit_times), compare_unit_time); - pager_open_if_enabled(); + pager_open(arg_no_pager, false); for (i = 0; i < (unsigned) n; i++) { char ts[FORMAT_TIMESPAN_MAX]; @@ -968,7 +1011,7 @@ static int analyze_time(sd_bus *bus) { return 0; } -static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop, const char *color, char* patterns[]) { +static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop, const char *color, char* patterns[], char* from_patterns[], char* to_patterns[]) { _cleanup_strv_free_ char **units = NULL; char **unit; int r; @@ -980,9 +1023,9 @@ static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop, match_patterns = strv_fnmatch(patterns, u->id, 0); - if (!strv_isempty(arg_dot_from_patterns) && + if (!strv_isempty(from_patterns) && !match_patterns && - !strv_fnmatch(arg_dot_from_patterns, u->id, 0)) + !strv_fnmatch(from_patterns, u->id, 0)) return 0; r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units); @@ -994,9 +1037,9 @@ static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop, match_patterns2 = strv_fnmatch(patterns, *unit, 0); - if (!strv_isempty(arg_dot_to_patterns) && + if (!strv_isempty(to_patterns) && !match_patterns2 && - !strv_fnmatch(arg_dot_to_patterns, *unit, 0)) + !strv_fnmatch(to_patterns, *unit, 0)) continue; if (!strv_isempty(patterns) && !match_patterns && !match_patterns2) @@ -1008,48 +1051,99 @@ static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop, return 0; } -static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[]) { +static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *from_patterns[], char *to_patterns[]) { int r; assert(bus); assert(u); - if (arg_dot == DEP_ORDER ||arg_dot == DEP_ALL) { - r = graph_one_property(bus, u, "After", "green", patterns); + if (IN_SET(arg_dot, DEP_ORDER, DEP_ALL)) { + r = graph_one_property(bus, u, "After", "green", patterns, from_patterns, to_patterns); if (r < 0) return r; } - if (arg_dot == DEP_REQUIRE ||arg_dot == DEP_ALL) { - r = graph_one_property(bus, u, "Requires", "black", patterns); + if (IN_SET(arg_dot, DEP_REQUIRE, DEP_ALL)) { + r = graph_one_property(bus, u, "Requires", "black", patterns, from_patterns, to_patterns); if (r < 0) return r; - r = graph_one_property(bus, u, "RequiresOverridable", "black", patterns); + r = graph_one_property(bus, u, "Requisite", "darkblue", patterns, from_patterns, to_patterns); if (r < 0) return r; - r = graph_one_property(bus, u, "RequisiteOverridable", "darkblue", patterns); + r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns); if (r < 0) return r; - r = graph_one_property(bus, u, "Wants", "grey66", patterns); + r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns); if (r < 0) return r; - r = graph_one_property(bus, u, "Conflicts", "red", patterns); - if (r < 0) - return r; - r = graph_one_property(bus, u, "ConflictedBy", "red", patterns); + } + + return 0; +} + +static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) { + _cleanup_strv_free_ char **expanded_patterns = NULL; + char **pattern; + int r; + + STRV_FOREACH(pattern, patterns) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *unit = NULL, *unit_id = NULL; + + if (strv_extend(&expanded_patterns, *pattern) < 0) + return log_oom(); + + if (string_is_glob(*pattern)) + continue; + + unit = unit_dbus_path_from_name(*pattern); + if (!unit) + return log_oom(); + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + unit, + "org.freedesktop.systemd1.Unit", + "Id", + &error, + &unit_id); if (r < 0) - return r; + return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r)); + + if (!streq(*pattern, unit_id)) { + if (strv_extend(&expanded_patterns, unit_id) < 0) + return log_oom(); + } } + *ret = expanded_patterns; + expanded_patterns = NULL; /* do not free */ + return 0; } static int dot(sd_bus *bus, char* patterns[]) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_strv_free_ char **expanded_patterns = NULL; + _cleanup_strv_free_ char **expanded_from_patterns = NULL; + _cleanup_strv_free_ char **expanded_to_patterns = NULL; int r; UnitInfo u; + r = expand_patterns(bus, patterns, &expanded_patterns); + if (r < 0) + return r; + + r = expand_patterns(bus, arg_dot_from_patterns, &expanded_from_patterns); + if (r < 0) + return r; + + r = expand_patterns(bus, arg_dot_to_patterns, &expanded_to_patterns); + if (r < 0) + return r; + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -1072,7 +1166,7 @@ static int dot(sd_bus *bus, char* patterns[]) { while ((r = bus_parse_unit_info(reply, &u)) > 0) { - r = graph_one(bus, &u, patterns); + r = graph_one(bus, &u, expanded_patterns, expanded_from_patterns, expanded_to_patterns); if (r < 0) return r; } @@ -1095,8 +1189,8 @@ static int dot(sd_bus *bus, char* patterns[]) { } static int dump(sd_bus *bus, char **args) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *text = NULL; int r; @@ -1105,7 +1199,7 @@ static int dump(sd_bus *bus, char **args) { return -E2BIG; } - pager_open_if_enabled(); + pager_open(arg_no_pager, false); r = sd_bus_call_method( bus, @@ -1116,10 +1210,8 @@ static int dump(sd_bus *bus, char **args) { &error, &reply, ""); - if (r < 0) { - log_error("Failed issue method call: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed issue method call: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &text); if (r < 0) @@ -1130,7 +1222,7 @@ static int dump(sd_bus *bus, char **args) { } static int set_log_level(sd_bus *bus, char **args) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -1150,17 +1242,42 @@ static int set_log_level(sd_bus *bus, char **args) { &error, "s", args[0]); - if (r < 0) { - log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); - return -EIO; + if (r < 0) + return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); + + return 0; +} + +static int set_log_target(sd_bus *bus, char **args) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(args); + + if (strv_length(args) != 1) { + log_error("This command expects one argument only."); + return -E2BIG; } + r = sd_bus_set_property( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "LogTarget", + &error, + "s", + args[0]); + if (r < 0) + return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); + return 0; } static void help(void) { - pager_open_if_enabled(); + pager_open(arg_no_pager, false); printf("%s [OPTIONS...] {COMMAND} ...\n\n" "Profile systemd, show unit dependencies, check unit files.\n\n" @@ -1184,7 +1301,8 @@ static void help(void) { " critical-chain Print a tree of the time critical chain of units\n" " plot Output SVG graphic showing service initialization\n" " dot Output dependency graph in dot(1) format\n" - " set-log-level LEVEL Set logging threshold for systemd\n" + " set-log-level LEVEL Set logging threshold for manager\n" + " set-log-target TARGET Set logging target for manager\n" " dump Output state serialization of service manager\n" " verify FILE... Check unit files for correctness\n" , program_invocation_short_name); @@ -1238,9 +1356,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_USER: arg_user = true; @@ -1328,12 +1444,12 @@ int main(int argc, char *argv[]) { if (streq_ptr(argv[optind], "verify")) r = verify_units(argv+optind+1, - arg_user ? MANAGER_USER : MANAGER_SYSTEM, + arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM, arg_man); else { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus); + r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; @@ -1353,6 +1469,8 @@ int main(int argc, char *argv[]) { r = dump(bus, argv+optind+1); else if (streq(argv[optind], "set-log-level")) r = set_log_level(bus, argv+optind+1); + else if (streq(argv[optind], "set-log-target")) + r = set_log_target(bus, argv+optind+1); else log_error("Unknown operation '%s'.", argv[optind]); } |