analyze.c revision 6a41c9e288fc9483aa98151338501f7654c229b6
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/***
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2010-2013 Lennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers Copyright 2013 Simon Peeters
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering***/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include <stdio.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <stdlib.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <getopt.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <locale.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <sys/utsname.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <fnmatch.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "sd-bus.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "bus-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "bus-error.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "install.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "log.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "build.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "strxcpyx.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "fileio.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "strv.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "unit-name.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "special.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "hashmap.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "pager.h"
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering#include "analyze-verify.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define SCALE_X (0.1 / 1000.0) /* pixels per us */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define SCALE_Y (20.0)
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
7085053a437456ab87d726f3697002dd811fdf7aDaniel Wallace#define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define svg(...) printf(__VA_ARGS__)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define svg_bar(class, x1, x2, y) \
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg(" <rect class=\"%s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", \
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (class), \
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SCALE_X * (x1), SCALE_Y * (y), \
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer SCALE_X * ((x2) - (x1)), SCALE_Y - 1.0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define svg_text(b, x, y, format, ...) \
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering do { \
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg(" <text class=\"%s\" x=\"%.03f\" y=\"%.03f\">", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg(format, ## __VA_ARGS__); \
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg("</text>\n"); \
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } while(false)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poetteringstatic enum dot {
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering DEP_ALL,
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering DEP_ORDER,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering DEP_REQUIRE
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering} arg_dot = DEP_ALL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic char** arg_dot_from_patterns = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic char** arg_dot_to_patterns = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic usec_t arg_fuzz = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool arg_no_pager = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic char *arg_host = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool arg_user = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool arg_man = true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstruct boot_times {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t firmware_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t loader_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t kernel_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t kernel_done_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t initrd_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t userspace_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t finish_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t security_start_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t security_finish_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t generators_start_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t generators_finish_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t unitsload_start_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t unitsload_finish_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering};
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstruct unit_times {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char *name;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t activating;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t activated;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t deactivated;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t deactivating;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering};
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstruct host_info {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char *hostname;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char *kernel_name;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers char *kernel_release;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek char *kernel_version;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers char *os_pretty_name;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers char *virtualization;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers char *architecture;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers};
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic void pager_open_if_enabled(void) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (arg_no_pager)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers pager_open(false);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversstatic int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers int r;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers assert(bus);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers assert(path);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers assert(interface);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers assert(property);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers assert(val);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_bus_get_property_trivial(
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers bus,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers "org.freedesktop.systemd1",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering path,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers interface,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering property,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &error,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers 't', val);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r < 0) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(bus);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers assert(path);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers assert(property);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers assert(strv);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers r = sd_bus_get_property_strv(
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers bus,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers "org.freedesktop.systemd1",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering path,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers "org.freedesktop.systemd1.Unit",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering property,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers &error,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering strv);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r < 0) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers log_error("Failed to get unit property %s: %s", property, bus_error_message(&error, -r));
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering return r;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int compare_unit_time(const void *a, const void *b) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return compare(((struct unit_times *)b)->time,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ((struct unit_times *)a)->time);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int compare_unit_start(const void *a, const void *b) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return compare(((struct unit_times *)a)->activating,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ((struct unit_times *)b)->activating);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void free_unit_times(struct unit_times *t, unsigned n) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct unit_times *p;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (p = t; p < t + n; p++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(p->name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(t);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int acquire_time_data(sd_bus *bus, struct unit_times **out) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r, c = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct unit_times *unit_times = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size_t size = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering UnitInfo u;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_bus_call_method(
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bus,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "org.freedesktop.systemd1",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "/org/freedesktop/systemd1",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "org.freedesktop.systemd1.Manager",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "ListUnits",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &error, &reply,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_error("Failed to list units: %s", bus_error_message(&error, -r));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bus_log_parse_error(r);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna while ((r = bus_parse_unit_info(reply, &u)) > 0) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna struct unit_times *t;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!GREEDY_REALLOC(unit_times, size, c+1)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = log_oom();
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering t = unit_times+c;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering t->name = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_cc(sizeof(usec_t) == sizeof(uint64_t));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (bus_get_uint64_property(bus, u.unit_path,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "org.freedesktop.systemd1.Unit",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "InactiveExitTimestampMonotonic",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &t->activating) < 0 ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bus_get_uint64_property(bus, u.unit_path,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "org.freedesktop.systemd1.Unit",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "ActiveEnterTimestampMonotonic",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &t->activated) < 0 ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bus_get_uint64_property(bus, u.unit_path,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "org.freedesktop.systemd1.Unit",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "ActiveExitTimestampMonotonic",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &t->deactivating) < 0 ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bus_get_uint64_property(bus, u.unit_path,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "org.freedesktop.systemd1.Unit",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "InactiveEnterTimestampMonotonic",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &t->deactivated) < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = -EIO;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t->activated >= t->activating)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering t->time = t->activated - t->activating;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (t->deactivated >= t->activating)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering t->time = t->deactivated - t->activating;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar t->time = 0;
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t->activating == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering continue;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering t->name = strdup(u.id);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t->name == NULL) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = log_oom();
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering c++;
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering }
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering if (r < 0) {
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering bus_log_parse_error(r);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *out = unit_times;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return c;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmekfail:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free_unit_times(unit_times, (unsigned) c);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering static struct boot_times times;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna static bool cached = false;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (cached)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna goto finish;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna assert_cc(sizeof(usec_t) == sizeof(uint64_t));
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer "FirmwareTimestampMonotonic",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna &times.firmware_time) < 0 ||
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "LoaderTimestampMonotonic",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna &times.loader_time) < 0 ||
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "KernelTimestamp",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna &times.kernel_time) < 0 ||
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "InitRDTimestampMonotonic",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna &times.initrd_time) < 0 ||
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "UserspaceTimestampMonotonic",
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek &times.userspace_time) < 0 ||
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek "FinishTimestampMonotonic",
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek &times.finish_time) < 0 ||
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "SecurityStartTimestampMonotonic",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna &times.security_start_time) < 0 ||
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna bus_get_uint64_property(bus,
8333c77edf8fd1654cd96f3f6ee0f078dd64b58bZbigniew Jędrzejewski-Szmek "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek "SecurityFinishTimestampMonotonic",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna &times.security_finish_time) < 0 ||
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna bus_get_uint64_property(bus,
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "GeneratorsStartTimestampMonotonic",
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers &times.generators_start_time) < 0 ||
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "GeneratorsFinishTimestampMonotonic",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna &times.generators_finish_time) < 0 ||
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "UnitsLoadStartTimestampMonotonic",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna &times.unitsload_start_time) < 0 ||
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek bus_get_uint64_property(bus,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "/org/freedesktop/systemd1",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "org.freedesktop.systemd1.Manager",
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna "UnitsLoadFinishTimestampMonotonic",
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek &times.unitsload_finish_time) < 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return -EIO;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek if (times.finish_time <= 0) {
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek log_error("Bootup is not yet finished. Please try again later.");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINPROGRESS;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (times.initrd_time)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering times.kernel_done_time = times.initrd_time;
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering times.kernel_done_time = times.userspace_time;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering cached = true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sieversfinish:
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers *bt = &times;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void free_host_info(struct host_info *hi) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(hi->hostname);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(hi->kernel_name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(hi->kernel_release);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(hi->kernel_version);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(hi->os_pretty_name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(hi->virtualization);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(hi->architecture);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free(hi);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int acquire_host_info(sd_bus *bus, struct host_info **hi) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct host_info *host;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering static const struct bus_properties_map hostname_map[] = {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering { "Hostname", "s", NULL, offsetof(struct host_info, hostname) },
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) },
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) },
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) },
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers { "OperatingSystemPrettyName", "s", NULL, offsetof(struct host_info, os_pretty_name) },
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering {}
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers };
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering static const struct bus_properties_map manager_map[] = {
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering {}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering };
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering host = new0(struct host_info, 1);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!host)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return log_oom();
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = bus_map_all_properties(bus,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "org.freedesktop.hostname1",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "/org/freedesktop/hostname1",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hostname_map,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering host);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = bus_map_all_properties(bus,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "org.freedesktop.systemd1",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering "/org/freedesktop/systemd1",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering manager_map,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering host);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto fail;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *hi = host;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringfail:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering free_host_info(host);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int pretty_boot_time(sd_bus *bus, char **_buf) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char ts[FORMAT_TIMESPAN_MAX];
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek struct boot_times *t;
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek static char buf[4096];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size_t size;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char *ptr;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = acquire_boot_times(bus, &t);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer ptr = buf;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size = sizeof(buf);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size = strpcpyf(&ptr, size, "Startup finished in ");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t->firmware_time)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC));
4a9e80b3b5d0d3c0cabac01c35db18d95f27c9c1Michał Górny if (t->loader_time)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t->kernel_time)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t->initrd_time > 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (t->kernel_time > 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ptr = strdup(buf);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!ptr)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return log_oom();
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *_buf = ptr;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic void svg_graph_box(double height, double begin, double end) {
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen long long i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* outside box, fill */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg("<rect class=\"box\" x=\"0\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SCALE_X * (end - begin), SCALE_Y * height);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers for (i = ((long long) (begin / 100000)) * 100000; i <= end; i+=100000) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers /* lines for each second */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (i % 5000000 == 0)
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (i % 1000000 == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int analyze_plot(sd_bus *bus) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct unit_times *times;
6b2b6f30e38d67b032d6bdc6b47ae05e143e96c5Michal Schmidt struct boot_times *boot;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct host_info *host = NULL;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering int n, m = 1, y=0;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering double width;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ char *pretty_times = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct unit_times *u;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = acquire_boot_times(bus, &boot);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (n < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return n;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers n = pretty_boot_time(bus, &pretty_times);
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering if (n < 0)
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering return n;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering n = acquire_host_info(bus, &host);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (n < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return n;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering n = acquire_time_data(bus, &times);
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer if (n <= 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering goto out;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering qsort(times, n, sizeof(struct unit_times), compare_unit_start);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering width = SCALE_X * (boot->firmware_time + boot->finish_time);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (width < 800.0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering width = 800.0;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (boot->firmware_time > boot->loader_time)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (boot->loader_time) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (width < 1000.0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering width = 1000.0;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
c62e11ce3966c55d23520b9f0785c7e839cf7f37Lennart Poettering if (boot->initrd_time)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (boot->kernel_time)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering for (u = times; u < times + n; u++) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering double text_start, text_width;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (u->activating < boot->userspace_time ||
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering u->activating > boot->finish_time) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering free(u->name);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering u->name = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering continue;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* If the text cannot fit on the left side then
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * increase the svg width so it fits on the right.
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering * TODO: calculate the text width more accurately */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering text_width = 8.0 * strlen(u->name);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering text_start = (boot->firmware_time + u->activating) * SCALE_X;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (text_width > text_start && text_width + text_start > width)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering width = text_width + text_start;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (u->deactivated > u->activating && u->deactivated <= boot->finish_time
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering && u->activated == 0 && u->deactivating == 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering u->activated = u->deactivating = u->deactivated;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (u->activated < u->activating || u->activated > boot->finish_time)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering u->activated = boot->finish_time;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (u->deactivating < u->activated || u->activated > boot->finish_time)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering u->deactivating = boot->finish_time;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (u->deactivated < u->deactivating || u->deactivated > boot->finish_time)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering u->deactivated = boot->finish_time;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering m++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg("<?xml version=\"1.0\" standalone=\"no\"?>\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg("<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" "
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "xmlns=\"http://www.w3.org/2000/svg\">\n\n",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering 80.0 + width, 150.0 + (m * SCALE_Y) +
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering 5 * SCALE_Y /* legend */);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* write some basic info as a comment, including some help */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg("<!-- This file is a systemd-analyze SVG file. It is best rendered in a -->\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "<!-- browser such as Chrome, Chromium or Firefox. Other applications -->\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "<!-- that render these files properly but much slower are ImageMagick, -->\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "<!-- gimp, inkscape, etc. To display the files on your system, just -->\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "<!-- point your browser to this file. -->\n\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "<!-- This plot was generated by systemd-analyze version %-16.16s -->\n\n", VERSION);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* style sheet */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg("<defs>\n <style type=\"text/css\">\n <![CDATA[\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect { stroke-width: 1; stroke-opacity: 0; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.background { fill: rgb(255,255,255); }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.activating { fill: rgb(255,0,0); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.active { fill: rgb(200,150,150); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.deactivating { fill: rgb(150,100,100); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.kernel { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.initrd { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.firmware { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.loader { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.userspace { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.security { fill: rgb(144,238,144); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.generators { fill: rgb(102,204,255); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.unitsload { fill: rgb( 82,184,255); fill-opacity: 0.7; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " line { stroke: rgb(64,64,64); stroke-width: 1; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering "// line.sec1 { }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " line.sec5 { stroke-width: 2; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " text { font-family: Verdana, Helvetica; font-size: 14px; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " text.left { font-family: Verdana, Helvetica; font-size: 14px; text-anchor: start; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " text.right { font-family: Verdana, Helvetica; font-size: 14px; text-anchor: end; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " text.sec { font-size: 10px; }\n"
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering " ]]>\n </style>\n</defs>\n\n");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg("<rect class=\"background\" width=\"100%%\" height=\"100%%\" />\n");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg("<text x=\"20\" y=\"30\">%s %s (%s %s %s) %s %s</text>",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering isempty(host->hostname) ? "" : host->hostname,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering isempty(host->kernel_name) ? "" : host->kernel_name,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering isempty(host->kernel_release) ? "" : host->kernel_release,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering isempty(host->kernel_version) ? "" : host->kernel_version,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering isempty(host->architecture) ? "" : host->architecture,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering isempty(host->virtualization) ? "" : host->virtualization);
82c1d8f4eb74ddd9be2c9b9b56d9dc564c599effLennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (boot->firmware_time) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers svg_bar("firmware", -(double) boot->firmware_time, -(double) boot->loader_time, y);
a86a47ce1f63476631635fbcbc10af8877172114Lennart Poettering svg_text(true, -(double) boot->firmware_time, y, "firmware");
a86a47ce1f63476631635fbcbc10af8877172114Lennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (boot->loader_time) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg_bar("loader", -(double) boot->loader_time, 0, y);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg_text(true, -(double) boot->loader_time, y, "loader");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering y++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (boot->kernel_time) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg_bar("kernel", 0, boot->kernel_done_time, y);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg_text(true, 0, y, "kernel");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering y++;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (boot->initrd_time) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering svg_bar("initrd", boot->initrd_time, boot->userspace_time, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(true, boot->initrd_time, y, "initrd");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("active", boot->userspace_time, boot->finish_time, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("security", boot->security_start_time, boot->security_finish_time, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("generators", boot->generators_start_time, boot->generators_finish_time, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("unitsload", boot->unitsload_start_time, boot->unitsload_finish_time, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(true, boot->userspace_time, y, "systemd");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (u = times; u < times + n; u++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char ts[FORMAT_TIMESPAN_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bool b;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!u->name)
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers continue;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers svg_bar("activating", u->activating, u->activated, y);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers svg_bar("active", u->activated, u->deactivating, y);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers svg_bar("deactivating", u->deactivating, u->deactivated, y);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers /* place the text on the left if we have passed the half of the svg width */
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering b = u->activating * SCALE_X < width / 2;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (u->time)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(b, u->activating, y, "%s (%s)",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(b, u->activating, y, "%s", u->name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
4b4bec19582c3ad2b7d25116f3c22c783274feadThomas Hindoe Paaboel Andersen
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg("</g>\n");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Legend */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg("<g transform=\"translate(20,100)\">\n");
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("activating", 0, 300000, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(true, 400000, y, "Activating");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("active", 0, 300000, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(true, 400000, y, "Active");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("deactivating", 0, 300000, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(true, 400000, y, "Deactivating");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("security", 0, 300000, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(true, 400000, y, "Setting up security module");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_bar("generators", 0, 300000, y);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering svg_text(true, 400000, y, "Generators");
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen y++;
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen svg_bar("unitsload", 0, 300000, y);
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen svg_text(true, 400000, y, "Loading unit files");
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen y++;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers svg("</g>\n\n");
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers svg("</svg>\n");
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers free_unit_times(times, (unsigned) n);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers n = 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sieversout:
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers free_host_info(host);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int list_dependencies_print(const char *name, unsigned int level, unsigned int branches,
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering bool last, struct unit_times *times, struct boot_times *boot) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned int i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = level; i != 0; i--)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering printf("%s", draw_special_char(branches & (1 << (i-1)) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (times) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (times->time)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED_ON, name,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (times->activated > boot->userspace_time)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers printf("%s", name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering printf("%s", name);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering printf("\n");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return 0;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering _cleanup_free_ char *path = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(bus);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(deps);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering path = unit_dbus_path_from_name(name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (path == NULL)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return bus_get_unit_property_strv(bus, path, "After", deps);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic Hashmap *unit_times_hashmap;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int list_dependencies_compare(const void *_a, const void *_b) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char **a = (const char**) _a, **b = (const char**) _b;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t usa = 0, usb = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct unit_times *times;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering times = hashmap_get(unit_times_hashmap, *a);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (times)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usa = times->activated;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering times = hashmap_get(unit_times_hashmap, *b);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (times)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usb = times->activated;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return usb - usa;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int list_dependencies_one(sd_bus *bus, const char *name, unsigned int level, char ***units,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned int branches) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_strv_free_ char **deps = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char **c;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t service_longest = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int to_print = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct unit_times *times;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct boot_times *boot;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (strv_extend(units, name))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return log_oom();
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = list_dependencies_get_dependencies(bus, name, &deps);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = acquire_boot_times(bus, &boot);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering STRV_FOREACH(c, deps) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering times = hashmap_get(unit_times_hashmap, *c);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (times
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering && times->activated
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering && times->activated <= boot->finish_time
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering && (times->activated >= service_longest
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering || service_longest == 0)) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering service_longest = times->activated;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (service_longest == 0 )
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return r;
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering STRV_FOREACH(c, deps) {
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner times = hashmap_get(unit_times_hashmap, *c);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (times && times->activated
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering && times->activated <= boot->finish_time
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering && (service_longest - times->activated) <= arg_fuzz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering to_print++;
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (!to_print)
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return r;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers STRV_FOREACH(c, deps) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering times = hashmap_get(unit_times_hashmap, *c);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!times
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers || !times->activated
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering || times->activated > boot->finish_time
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers || service_longest - times->activated > arg_fuzz)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering continue;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering to_print--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
r = list_dependencies_print(*c, level, branches, to_print == 0, times, boot);
if (r < 0)
return r;
if (strv_contains(*units, *c)) {
r = list_dependencies_print("...", level + 1, (branches << 1) | (to_print ? 1 : 0),
true, NULL, boot);
if (r < 0)
return r;
continue;
}
r = list_dependencies_one(bus, *c, level + 1, units,
(branches << 1) | (to_print ? 1 : 0));
if (r < 0)
return r;
if (!to_print)
break;
}
return 0;
}
static int list_dependencies(sd_bus *bus, const char *name) {
_cleanup_strv_free_ char **units = NULL;
char ts[FORMAT_TIMESPAN_MAX];
struct unit_times *times;
int r;
const char *path, *id;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
struct boot_times *boot;
assert(bus);
path = unit_dbus_path_from_name(name);
if (path == NULL)
return -ENOMEM;
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
path,
"org.freedesktop.systemd1.Unit",
"Id",
&error,
&reply,
"s");
if (r < 0) {
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)
return bus_log_parse_error(r);
times = hashmap_get(unit_times_hashmap, id);
r = acquire_boot_times(bus, &boot);
if (r < 0)
return r;
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);
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
printf("%s\n", id);
}
return list_dependencies_one(bus, name, 0, &units, 0);
}
static int analyze_critical_chain(sd_bus *bus, char *names[]) {
struct unit_times *times;
unsigned int i;
Hashmap *h;
int n, r;
n = acquire_time_data(bus, &times);
if (n <= 0)
return n;
h = hashmap_new(string_hash_func, string_compare_func);
if (!h)
return -ENOMEM;
for (i = 0; i < (unsigned)n; i++) {
r = hashmap_put(h, times[i].name, &times[i]);
if (r < 0)
return r;
}
unit_times_hashmap = h;
pager_open_if_enabled();
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");
if (!strv_isempty(names)) {
char **name;
STRV_FOREACH(name, names)
list_dependencies(bus, *name);
} else
list_dependencies(bus, SPECIAL_DEFAULT_TARGET);
hashmap_free(h);
free_unit_times(times, (unsigned) n);
return 0;
}
static int analyze_blame(sd_bus *bus) {
struct unit_times *times;
unsigned i;
int n;
n = acquire_time_data(bus, &times);
if (n <= 0)
return n;
qsort(times, n, sizeof(struct unit_times), compare_unit_time);
pager_open_if_enabled();
for (i = 0; i < (unsigned) n; i++) {
char ts[FORMAT_TIMESPAN_MAX];
if (times[i].time > 0)
printf("%16s %s\n", format_timespan(ts, sizeof(ts), times[i].time, USEC_PER_MSEC), times[i].name);
}
free_unit_times(times, (unsigned) n);
return 0;
}
static int analyze_time(sd_bus *bus) {
_cleanup_free_ char *buf = NULL;
int r;
r = pretty_boot_time(bus, &buf);
if (r < 0)
return r;
puts(buf);
return 0;
}
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;
assert(u);
assert(prop);
assert(color);
r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units);
if (r < 0)
return r;
STRV_FOREACH(unit, units) {
char **p;
bool match_found;
if (!strv_isempty(arg_dot_from_patterns)) {
match_found = false;
STRV_FOREACH(p, arg_dot_from_patterns)
if (fnmatch(*p, u->id, 0) == 0) {
match_found = true;
break;
}
if (!match_found)
continue;
}
if (!strv_isempty(arg_dot_to_patterns)) {
match_found = false;
STRV_FOREACH(p, arg_dot_to_patterns)
if (fnmatch(*p, *unit, 0) == 0) {
match_found = true;
break;
}
if (!match_found)
continue;
}
if (!strv_isempty(patterns)) {
match_found = false;
STRV_FOREACH(p, patterns)
if (fnmatch(*p, u->id, 0) == 0 || fnmatch(*p, *unit, 0) == 0) {
match_found = true;
break;
}
if (!match_found)
continue;
}
printf("\t\"%s\"->\"%s\" [color=\"%s\"];\n", u->id, *unit, color);
}
return 0;
}
static int graph_one(sd_bus *bus, const UnitInfo *u, char *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 (r < 0)
return r;
}
if (arg_dot == DEP_REQUIRE ||arg_dot == DEP_ALL) {
r = graph_one_property(bus, u, "Requires", "black", patterns);
if (r < 0)
return r;
r = graph_one_property(bus, u, "RequiresOverridable", "black", patterns);
if (r < 0)
return r;
r = graph_one_property(bus, u, "RequisiteOverridable", "darkblue", patterns);
if (r < 0)
return r;
r = graph_one_property(bus, u, "Wants", "grey66", 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);
if (r < 0)
return r;
}
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;
int r;
UnitInfo u;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"ListUnits",
&error,
&reply,
"");
if (r < 0) {
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 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");
log_info(" Color legend: black = Requires\n"
" dark blue = Requisite\n"
" dark grey = Wants\n"
" red = Conflicts\n"
" green = After\n");
if (on_tty())
log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
"-- Try a shell pipeline like 'systemd-analyze dot | dot -Tsvg > systemd.svg'!\n");
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;
const char *text = NULL;
int r;
if (!strv_isempty(args)) {
log_error("Too many arguments.");
return -E2BIG;
}
pager_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"Dump",
&error,
&reply,
"");
if (r < 0) {
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)
return bus_log_parse_error(r);
fputs(text, stdout);
return 0;
}
static int set_log_level(sd_bus *bus, char **args) {
_cleanup_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",
"LogLevel",
&error,
"s",
args[0]);
if (r < 0) {
log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
return -EIO;
}
return 0;
}
static void help(void) {
pager_open_if_enabled();
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Profile systemd, show unit dependencies, check unit files.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --system Operate on system systemd instance\n"
" --user Operate on user systemd instance\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-man Do not check for existence of man pages\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"
" verify FILE... Check unit files for correctness\n"
, program_invocation_short_name);
/* When updating this list, including descriptions, apply
* changes to shell-completion/bash/systemd-analyze and
* shell-completion/zsh/_systemd-analyze too. */
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_ORDER,
ARG_REQUIRE,
ARG_USER,
ARG_SYSTEM,
ARG_DOT_FROM_PATTERN,
ARG_DOT_TO_PATTERN,
ARG_FUZZ,
ARG_NO_PAGER,
ARG_NO_MAN,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "order", no_argument, NULL, ARG_ORDER },
{ "require", no_argument, NULL, ARG_REQUIRE },
{ "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "from-pattern", required_argument, NULL, ARG_DOT_FROM_PATTERN },
{ "to-pattern", required_argument, NULL, ARG_DOT_TO_PATTERN },
{ "fuzz", required_argument, NULL, ARG_FUZZ },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-man", no_argument, NULL, ARG_NO_MAN },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{}
};
int r, c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case ARG_USER:
arg_user = true;
break;
case ARG_SYSTEM:
arg_user = false;
break;
case ARG_ORDER:
arg_dot = DEP_ORDER;
break;
case ARG_REQUIRE:
arg_dot = DEP_REQUIRE;
break;
case ARG_DOT_FROM_PATTERN:
if (strv_extend(&arg_dot_from_patterns, optarg) < 0)
return log_oom();
break;
case ARG_DOT_TO_PATTERN:
if (strv_extend(&arg_dot_to_patterns, optarg) < 0)
return log_oom();
break;
case ARG_FUZZ:
r = parse_sec(optarg, &arg_fuzz);
if (r < 0)
return r;
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
break;
case 'M':
arg_transport = BUS_TRANSPORT_CONTAINER;
arg_host = optarg;
break;
case ARG_NO_MAN:
arg_man = false;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option code.");
}
return 1; /* work to do */
}
int main(int argc, char *argv[]) {
int r;
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C"); /* we want to format/parse floats in C style */
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
if (streq_ptr(argv[optind], "verify"))
r = verify_units(argv+optind+1,
arg_user ? SYSTEMD_USER : SYSTEMD_SYSTEM,
arg_man);
else {
_cleanup_bus_close_unref_ sd_bus *bus = NULL;
r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus);
if (r < 0) {
log_error("Failed to create bus connection: %s", strerror(-r));
goto finish;
}
if (!argv[optind] || streq(argv[optind], "time"))
r = analyze_time(bus);
else if (streq(argv[optind], "blame"))
r = analyze_blame(bus);
else if (streq(argv[optind], "critical-chain"))
r = analyze_critical_chain(bus, argv+optind+1);
else if (streq(argv[optind], "plot"))
r = analyze_plot(bus);
else if (streq(argv[optind], "dot"))
r = dot(bus, argv+optind+1);
else if (streq(argv[optind], "dump"))
r = dump(bus, argv+optind+1);
else if (streq(argv[optind], "set-log-level"))
r = set_log_level(bus, argv+optind+1);
else
log_error("Unknown operation '%s'.", argv[optind]);
}
finish:
pager_close();
strv_free(arg_dot_from_patterns);
strv_free(arg_dot_to_patterns);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}