X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fanalyze%2Fanalyze.c;h=4c5fcfe8c2eb6510c4ec3aa06e416579123c8d3d;hb=7e690cefd4f09bb6370f91611f623adea841bdf4;hp=e278a64d7646ce6d50fe5e4b3eee9357f23fafe5;hpb=cc27380c1e09bd51380fbeb168d8315cc806e0ab;p=elogind.git
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index e278a64d7..4c5fcfe8c 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -43,7 +43,7 @@
#include "pager.h"
#define SCALE_X (0.1 / 1000.0) /* pixels per us */
-#define SCALE_Y 20.0
+#define SCALE_Y (20.0)
#define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0))
@@ -62,7 +62,6 @@
svg("\n"); \
} while(false)
-static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
static enum dot {
DEP_ALL,
DEP_ORDER,
@@ -72,6 +71,9 @@ static char** arg_dot_from_patterns = NULL;
static char** arg_dot_to_patterns = NULL;
static usec_t arg_fuzz = 0;
static bool arg_no_pager = false;
+static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
+static char *arg_host = NULL;
+static bool arg_user = false;
struct boot_times {
usec_t firmware_time;
@@ -81,25 +83,14 @@ struct boot_times {
usec_t initrd_time;
usec_t userspace_time;
usec_t finish_time;
+ usec_t security_start_time;
+ usec_t security_finish_time;
usec_t generators_start_time;
usec_t generators_finish_time;
usec_t unitsload_start_time;
usec_t unitsload_finish_time;
};
-struct unit_info {
- const char *id;
- const char *description;
- const char *load_state;
- const char *active_state;
- const char *sub_state;
- const char *following;
- const char *unit_path;
- uint32_t job_id;
- const char *job_type;
- const char *job_path;
-};
-
struct unit_times {
char *name;
usec_t activating;
@@ -109,6 +100,16 @@ struct unit_times {
usec_t time;
};
+struct host_info {
+ char *hostname;
+ char *kernel_name;
+ char *kernel_release;
+ char *kernel_version;
+ char *os_pretty_name;
+ char *virtualization;
+ char *architecture;
+};
+
static void pager_open_if_enabled(void) {
if (arg_no_pager)
@@ -121,6 +122,12 @@ static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *in
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
+ assert(bus);
+ assert(path);
+ assert(interface);
+ assert(property);
+ assert(val);
+
r = sd_bus_get_property_trivial(
bus,
"org.freedesktop.systemd1",
@@ -138,6 +145,31 @@ static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *in
return 0;
}
+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;
+ int r;
+
+ assert(bus);
+ assert(path);
+ assert(property);
+ assert(strv);
+
+ r = sd_bus_get_property_strv(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.systemd1.Unit",
+ property,
+ &error,
+ strv);
+ if (r < 0) {
+ log_error("Failed to get unit property %s: %s", property, bus_error_message(&error, -r));
+ return r;
+ }
+
+ return 0;
+}
+
static int compare_unit_time(const void *a, const void *b) {
return compare(((struct unit_times *)b)->time,
((struct unit_times *)a)->time);
@@ -148,21 +180,6 @@ static int compare_unit_start(const void *a, const void *b) {
((struct unit_times *)b)->activating);
}
-static int get_os_name(char **_n) {
- char *n = NULL;
- int r;
-
- r = parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &n, NULL);
- if (r < 0)
- return r;
-
- if (!n)
- return -ENOENT;
-
- *_n = n;
- return 0;
-}
-
static void free_unit_times(struct unit_times *t, unsigned n) {
struct unit_times *p;
@@ -172,109 +189,41 @@ static void free_unit_times(struct unit_times *t, unsigned n) {
free(t);
}
-static int bus_parse_unit_info(sd_bus_message *message, struct unit_info *u) {
- int r = 0;
-
- assert(message);
- assert(u);
-
- r = sd_bus_message_read(message, "(ssssssouso)", &u->id,
- &u->description,
- &u->load_state,
- &u->active_state,
- &u->sub_state,
- &u->following,
- &u->unit_path,
- &u->job_id,
- &u->job_type,
- &u->job_path);
- if (r < 0) {
- log_error("Failed to parse message as unit_info.");
- return -EIO;
- }
-
- return r;
-}
-
-static int bus_get_unit_property_strv(sd_bus *bus, const char *unit_path, const char *prop, char ***strv) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
- const char *s;
-
- r = sd_bus_get_property(
- bus,
- "org.freedesktop.systemd1",
- unit_path,
- "org.freedesktop.systemd1.Unit",
- prop,
- &error,
- &reply,
- "as");
- if (r < 0) {
- log_error("Failed to get unit property: %s %s", prop, bus_error_message(&error, -r));
- return r;
- }
-
- r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_read(reply, "s", &s)) > 0) {
- r = strv_extend(strv, s);
- if (r < 0) {
- log_oom();
- return r;
- }
- }
-
- return r;
-}
-
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, n_units = 0;
+ int r, c = 0;
struct unit_times *unit_times = NULL;
- struct unit_info u;
+ 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,
- "");
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ListUnits",
+ &error, &reply,
+ NULL);
if (r < 0) {
- log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
- goto fail;
+ 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)
- goto fail;
+ if (r < 0) {
+ bus_log_parse_error(r);
+ goto fail;
+ }
while ((r = bus_parse_unit_info(reply, &u)) > 0) {
struct unit_times *t;
- if (r < 0)
- goto fail;
-
- if (c >= n_units) {
- struct unit_times *w;
-
- n_units = MAX(2*c, 16);
- w = realloc(unit_times, sizeof(struct unit_times) * n_units);
-
- if (!w) {
- r = log_oom();
- goto fail;
- }
-
- unit_times = w;
+ if (!GREEDY_REALLOC(unit_times, size, c+1)) {
+ r = log_oom();
+ goto fail;
}
+
t = unit_times+c;
t->name = NULL;
@@ -317,6 +266,10 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
}
c++;
}
+ if (r < 0) {
+ bus_log_parse_error(r);
+ goto fail;
+ }
*out = unit_times;
return c;
@@ -365,6 +318,16 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
"org.freedesktop.systemd1.Manager",
"FinishTimestampMonotonic",
×.finish_time) < 0 ||
+ bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SecurityStartTimestampMonotonic",
+ ×.security_start_time) < 0 ||
+ bus_get_uint64_property(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SecurityFinishTimestampMonotonic",
+ ×.security_finish_time) < 0 ||
bus_get_uint64_property(bus,
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
@@ -389,7 +352,7 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
if (times.finish_time <= 0) {
log_error("Bootup is not yet finished. Please try again later.");
- return -EAGAIN;
+ return -EINPROGRESS;
}
if (times.initrd_time)
@@ -404,6 +367,63 @@ finish:
return 0;
}
+static void free_host_info(struct host_info *hi) {
+ free(hi->hostname);
+ free(hi->kernel_name);
+ free(hi->kernel_release);
+ free(hi->kernel_version);
+ free(hi->os_pretty_name);
+ free(hi->virtualization);
+ free(hi->architecture);
+ free(hi);
+}
+
+static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
+ int r;
+ struct host_info *host;
+
+ 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) },
+ { "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) },
+ {}
+ };
+
+ host = new0(struct host_info, 1);
+ if (!host)
+ return log_oom();
+
+ r = bus_map_all_properties(bus,
+ "org.freedesktop.hostname1",
+ "/org/freedesktop/hostname1",
+ hostname_map,
+ host);
+ if (r < 0)
+ goto fail;
+
+ r = bus_map_all_properties(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ manager_map,
+ host);
+ if (r < 0)
+ goto fail;
+
+ *hi = host;
+ return 0;
+fail:
+ free_host_info(host);
+ return r;
+}
+
static int pretty_boot_time(sd_bus *bus, char **_buf) {
char ts[FORMAT_TIMESPAN_MAX];
struct boot_times *t;
@@ -469,10 +489,10 @@ static void svg_graph_box(double height, double begin, double end) {
static int analyze_plot(sd_bus *bus) {
struct unit_times *times;
struct boot_times *boot;
- struct utsname name;
+ struct host_info *host = NULL;
int n, m = 1, y=0;
double width;
- _cleanup_free_ char *pretty_times = NULL, *osname = NULL;
+ _cleanup_free_ char *pretty_times = NULL;
struct unit_times *u;
n = acquire_boot_times(bus, &boot);
@@ -483,12 +503,13 @@ static int analyze_plot(sd_bus *bus) {
if (n < 0)
return n;
- get_os_name(&osname);
- assert_se(uname(&name) >= 0);
+ n = acquire_host_info(bus, &host);
+ if (n < 0)
+ return n;
n = acquire_time_data(bus, ×);
if (n <= 0)
- return n;
+ goto out;
qsort(times, n, sizeof(struct unit_times), compare_unit_start);
@@ -567,6 +588,7 @@ static int analyze_plot(sd_bus *bus) {
" rect.firmware { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
" rect.loader { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
" rect.userspace { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
+ " rect.security { fill: rgb(144,238,144); fill-opacity: 0.7; }\n"
" rect.generators { fill: rgb(102,204,255); fill-opacity: 0.7; }\n"
" rect.unitsload { fill: rgb( 82,184,255); fill-opacity: 0.7; }\n"
" rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n"
@@ -582,12 +604,17 @@ static int analyze_plot(sd_bus *bus) {
svg("\n");
svg("%s", pretty_times);
- svg("%s %s (%s %s) %s",
- isempty(osname) ? "Linux" : osname,
- name.nodename, name.release, name.version, name.machine);
+ svg("%s %s (%s %s %s) %s %s",
+ 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);
svg("\n", 20.0 + (SCALE_X * boot->firmware_time));
- svg_graph_box(m, -boot->firmware_time, boot->finish_time);
+ svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time);
if (boot->firmware_time) {
svg_bar("firmware", -(double) boot->firmware_time, -(double) boot->loader_time, y);
@@ -610,6 +637,7 @@ static int analyze_plot(sd_bus *bus) {
y++;
}
svg_bar("active", boot->userspace_time, boot->finish_time, y);
+ svg_bar("security", boot->security_start_time, boot->security_finish_time, y);
svg_bar("generators", boot->generators_start_time, boot->generators_finish_time, y);
svg_bar("unitsload", boot->unitsload_start_time, boot->unitsload_finish_time, y);
svg_text(true, boot->userspace_time, y, "systemd");
@@ -636,7 +664,10 @@ static int analyze_plot(sd_bus *bus) {
y++;
}
+ svg("\n");
+
/* Legend */
+ svg("\n");
y++;
svg_bar("activating", 0, 300000, y);
svg_text(true, 400000, y, "Activating");
@@ -647,6 +678,9 @@ static int analyze_plot(sd_bus *bus) {
svg_bar("deactivating", 0, 300000, y);
svg_text(true, 400000, y, "Deactivating");
y++;
+ svg_bar("security", 0, 300000, y);
+ svg_text(true, 400000, y, "Setting up security module");
+ y++;
svg_bar("generators", 0, 300000, y);
svg_text(true, 400000, y, "Generators");
y++;
@@ -656,11 +690,14 @@ static int analyze_plot(sd_bus *bus) {
svg("\n\n");
- svg("");
+ svg("\n");
free_unit_times(times, (unsigned) n);
- return 0;
+ n = 0;
+out:
+ free_host_info(host);
+ return n;
}
static int list_dependencies_print(const char *name, unsigned int level, unsigned int branches,
@@ -669,7 +706,7 @@ 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_VERT : DRAW_TREE_SPACE));
+ printf("%s", draw_special_char(branches & (1 << (i-1)) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE));
printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
@@ -682,17 +719,15 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne
printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
else
printf("%s", name);
- } else printf("%s", name);
+ } else
+ printf("%s", name);
printf("\n");
return 0;
}
static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) {
- _cleanup_free_ char *path;
-
- int r = 0;
- char **ret = NULL;
+ _cleanup_free_ char *path = NULL;
assert(bus);
assert(name);
@@ -700,15 +735,9 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
path = unit_dbus_path_from_name(name);
if (path == NULL)
- return -EINVAL;
-
- r = bus_get_unit_property_strv(bus, path, "After", &ret);
+ return -ENOMEM;
- if (r < 0)
- strv_free(ret);
- else
- *deps = ret;
- return r;
+ return bus_get_unit_property_strv(bus, path, "After", deps);
}
static Hashmap *unit_times_hashmap;
@@ -738,7 +767,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev
struct unit_times *times;
struct boot_times *boot;
- if(strv_extend(units, name))
+ if (strv_extend(units, name))
return log_oom();
r = list_dependencies_get_dependencies(bus, name, &deps);
@@ -775,7 +804,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev
}
}
- if(!to_print)
+ if (!to_print)
return r;
STRV_FOREACH(c, deps) {
@@ -825,7 +854,7 @@ static int list_dependencies(sd_bus *bus, const char *name) {
path = unit_dbus_path_from_name(name);
if (path == NULL)
- return -EINVAL;
+ return -ENOMEM;
r = sd_bus_get_property(
bus,
@@ -837,15 +866,13 @@ static int list_dependencies(sd_bus *bus, const char *name) {
&reply,
"s");
if (r < 0) {
- log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
+ log_error("Failed to get ID: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_read(reply, "s", &id);
- if (r < 0) {
- log_error("Failed to parse reply.");
- return r;
- }
+ if (r < 0)
+ return bus_log_parse_error(r);
times = hashmap_get(unit_times_hashmap, id);
@@ -868,9 +895,9 @@ static int list_dependencies(sd_bus *bus, const char *name) {
static int analyze_critical_chain(sd_bus *bus, char *names[]) {
struct unit_times *times;
- int n, r;
unsigned int i;
Hashmap *h;
+ int n, r;
n = acquire_time_data(bus, ×);
if (n <= 0)
@@ -940,7 +967,7 @@ static int analyze_time(sd_bus *bus) {
return 0;
}
-static int graph_one_property(sd_bus *bus, const struct unit_info *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[]) {
_cleanup_strv_free_ char **units = NULL;
char **unit;
int r;
@@ -950,9 +977,8 @@ static int graph_one_property(sd_bus *bus, const struct unit_info *u, const char
assert(color);
r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units);
- if (r < 0) {
- return -r;
- }
+ if (r < 0)
+ return r;
STRV_FOREACH(unit, units) {
char **p;
@@ -1002,7 +1028,7 @@ static int graph_one_property(sd_bus *bus, const struct unit_info *u, const char
return 0;
}
-static int graph_one(sd_bus *bus, const struct unit_info *u, char *patterns[]) {
+static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[]) {
int r;
assert(bus);
@@ -1042,7 +1068,7 @@ 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;
int r;
- struct unit_info u;
+ UnitInfo u;
r = sd_bus_call_method(
bus,
@@ -1054,21 +1080,24 @@ static int dot(sd_bus *bus, char* patterns[]) {
&reply,
"");
if (r < 0) {
- log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
- return r;
+ log_error("Failed to list units: %s", bus_error_message(&error, -r));
+ return r;
}
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
if (r < 0)
- return r;
+ return bus_log_parse_error(r);
printf("digraph systemd {\n");
while ((r = bus_parse_unit_info(reply, &u)) > 0) {
+
r = graph_one(bus, &u, patterns);
if (r < 0)
return r;
}
+ if (r < 0)
+ return bus_log_parse_error(r);
printf("}\n");
@@ -1084,6 +1113,7 @@ static int dot(sd_bus *bus, char* patterns[]) {
return 0;
}
+
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;
@@ -1107,15 +1137,13 @@ static int dump(sd_bus *bus, char **args) {
&reply,
"");
if (r < 0) {
- log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
- return r;
+ log_error("Failed issue method call: %s", bus_error_message(&error, -r));
+ return r;
}
r = sd_bus_message_read(reply, "s", &text);
- if (r < 0) {
- log_error("Failed to parse reply");
- return r;
- }
+ if (r < 0)
+ return bus_log_parse_error(r);
fputs(text, stdout);
return 0;
@@ -1124,7 +1152,6 @@ 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;
int r;
- const char* value;
assert(bus);
assert(args);
@@ -1134,8 +1161,6 @@ static int set_log_level(sd_bus *bus, char **args) {
return -E2BIG;
}
- value = args[0];
-
r = sd_bus_set_property(
bus,
"org.freedesktop.systemd1",
@@ -1144,7 +1169,7 @@ static int set_log_level(sd_bus *bus, char **args) {
"LogLevel",
&error,
"s",
- value);
+ args[0]);
if (r < 0) {
log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
return -EIO;
@@ -1153,44 +1178,46 @@ static int set_log_level(sd_bus *bus, char **args) {
return 0;
}
-static void analyze_help(void) {
+static int help(void) {
pager_open_if_enabled();
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
- "Process systemd profiling information\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --system Connect to system manager\n"
- " --user Connect to user service manager\n"
- " --order When generating a dependency graph, show only order\n"
- " --require When generating a dependency graph, show only requirement\n"
+ "Process systemd profiling information.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --no-pager Do not pipe output into a pager\n"
+ " --system Connect to system manager\n"
+ " --user Connect to user manager\n"
+ " -H --host=[USER@]HOST Operate on remote host\n"
+ " -M --machine=CONTAINER Operate on local container\n"
+ " --order When generating a dependency graph, show only order\n"
+ " --require When generating a dependency graph, show only requirement\n"
" --from-pattern=GLOB, --to-pattern=GLOB\n"
- " When generating a dependency graph, filter only origins\n"
- " or destinations, respectively\n"
- " --fuzz=TIMESPAN When printing the tree of the critical chain, print also\n"
- " services, which finished TIMESPAN earlier, than the\n"
- " latest in the branch. The unit of TIMESPAN is seconds\n"
- " unless specified with a different unit, i.e. 50ms\n"
- " --no-pager Do not pipe output into a pager\n\n"
+ " When generating a dependency graph, filter only origins\n"
+ " or destinations, respectively\n"
+ " --fuzz=TIMESPAN When printing the tree of the critical chain, print also\n"
+ " services, which finished TIMESPAN earlier, than the\n"
+ " latest in the branch. The unit of TIMESPAN is seconds\n"
+ " unless specified with a different unit, i.e. 50ms\n\n"
"Commands:\n"
- " time Print time spent in the kernel before reaching userspace\n"
- " blame Print list of running units ordered by time to init\n"
- " 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"
- " dump Output state serialization of service manager\n",
+ " time Print time spent in the kernel before reaching userspace\n"
+ " blame Print list of running units ordered by time to init\n"
+ " 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"
+ " dump Output state serialization of service manager\n",
program_invocation_short_name);
/* When updating this list, including descriptions, apply
* changes to shell-completion/bash/systemd and
* shell-completion/systemd-zsh-completion.zsh too. */
+
+ return 0;
}
static int parse_argv(int argc, char *argv[]) {
- int r;
-
enum {
ARG_VERSION = 0x100,
ARG_ORDER,
@@ -1214,29 +1241,34 @@ static int parse_argv(int argc, char *argv[]) {
{ "to-pattern", required_argument, NULL, ARG_DOT_TO_PATTERN },
{ "fuzz", required_argument, NULL, ARG_FUZZ },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { NULL, 0, NULL, 0 }
+ { "host", required_argument, NULL, 'H' },
+ { "machine", required_argument, NULL, 'M' },
+ {}
};
+ int r, c;
+
assert(argc >= 0);
assert(argv);
- for (;;) {
- switch (getopt_long(argc, argv, "h", options, NULL)) {
+ while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
+
+ switch (c) {
case 'h':
- analyze_help();
- return 0;
+ return help();
case ARG_VERSION:
- puts(PACKAGE_STRING "\n" SYSTEMD_FEATURES);
+ puts(PACKAGE_STRING);
+ puts(SYSTEMD_FEATURES);
return 0;
case ARG_USER:
- arg_scope = UNIT_FILE_USER;
+ arg_user = true;
break;
case ARG_SYSTEM:
- arg_scope = UNIT_FILE_SYSTEM;
+ arg_user = false;
break;
case ARG_ORDER:
@@ -1269,8 +1301,15 @@ static int parse_argv(int argc, char *argv[]) {
arg_no_pager = true;
break;
- case -1:
- return 1;
+ case 'H':
+ arg_transport = BUS_TRANSPORT_REMOTE;
+ arg_host = optarg;
+ break;
+
+ case 'M':
+ arg_transport = BUS_TRANSPORT_CONTAINER;
+ arg_host = optarg;
+ break;
case '?':
return -EINVAL;
@@ -1279,6 +1318,8 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
}
+
+ return 1;
}
int main(int argc, char *argv[]) {
@@ -1294,13 +1335,9 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- if (arg_scope == UNIT_FILE_SYSTEM)
- r = sd_bus_open_system(&bus);
- else
- r = sd_bus_open_user(&bus);
-
+ r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
if (r < 0) {
- log_error("Failed to connect to bus: %s", strerror(-r));
+ log_error("Failed to create bus connection: %s", strerror(-r));
goto finish;
}