analyze.c revision b5cfa7408c4cb68e9bb232fc34b07fd03c915617
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/***
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering This file is part of systemd.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Copyright 2010-2013 Lennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers Copyright 2013 Simon Peeters
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is free software; you can redistribute it and/or modify it
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering under the terms of the GNU Lesser General Public License as published by
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (at your option) any later version.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is distributed in the hope that it will be useful, but
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Lesser General Public License for more details.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering You should have received a copy of the GNU Lesser General Public License
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering***/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <stdio.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <stdlib.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <getopt.h>
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include <locale.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <sys/utsname.h>
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen#include <fnmatch.h>
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen#include "sd-bus.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "bus-util.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "bus-error.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "install.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "log.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "build.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "util.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "strxcpyx.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "fileio.h"
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering#include "strv.h"
7085053a437456ab87d726f3697002dd811fdf7aDaniel Wallace#include "unit-name.h"
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering#include "special.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "hashmap.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "pager.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#define SCALE_X (0.1 / 1000.0) /* pixels per us */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#define SCALE_Y 20.0
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer#define compare(a, b) (((a) > (b))? 1 : (((b) > (a))? -1 : 0))
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#define svg(...) printf(__VA_ARGS__)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#define svg_bar(class, x1, x2, y) \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(" <rect class=\"%s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n", \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (class), \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * (x1), SCALE_Y * (y), \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * ((x2) - (x1)), SCALE_Y - 1.0)
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering#define svg_text(b, x, y, format, ...) \
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering do { \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart 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); \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(format, ## __VA_ARGS__); \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg("</text>\n"); \
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering } while(false)
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversstatic enum dot {
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers DEP_ALL,
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers DEP_ORDER,
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers DEP_REQUIRE
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers} arg_dot = DEP_ALL;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversstatic char** arg_dot_from_patterns = NULL;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversstatic char** arg_dot_to_patterns = NULL;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversstatic usec_t arg_fuzz = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic bool arg_no_pager = false;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversstatic char *arg_host = NULL;
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sieversstatic bool arg_user = false;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstruct boot_times {
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden usec_t firmware_time;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering usec_t loader_time;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering usec_t kernel_time;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering usec_t kernel_done_time;
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering usec_t initrd_time;
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering usec_t userspace_time;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering usec_t finish_time;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering usec_t security_start_time;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering usec_t security_finish_time;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering usec_t generators_start_time;
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers usec_t generators_finish_time;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering usec_t unitsload_start_time;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering usec_t unitsload_finish_time;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering};
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poetteringstruct unit_times {
3e5e74d5b7f6fcbeff7b6e4e06abd931aab14c48Shawn Landden char *name;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden usec_t activating;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden usec_t activated;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden usec_t deactivated;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering usec_t deactivating;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden usec_t time;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden};
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poetteringstatic void pager_open_if_enabled(void) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden if (arg_no_pager)
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek return;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek pager_open(false);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek}
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landdenstatic int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden int r;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(bus);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers assert(path);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers assert(interface);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(property);
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering assert(val);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek r = sd_bus_get_property_trivial(
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers bus,
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden "org.freedesktop.systemd1",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering path,
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek interface,
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek property,
2667cc25896a15f82f9f1583e80d416beb1316e1Thomas Hindoe Paaboel Andersen &error,
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering 't', val);
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering if (r < 0) {
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering log_error("Failed to parse reply: %s", bus_error_message(&error, -r));
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return r;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering }
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return 0;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering}
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmekstatic int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) {
b90930c73b1c82a3dc4d4f2603799993f042aaffLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int r;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek assert(bus);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers assert(path);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers assert(property);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers assert(strv);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers r = sd_bus_get_property_strv(
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus,
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers "org.freedesktop.systemd1",
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers path,
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers "org.freedesktop.systemd1.Unit",
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers property,
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John &error,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strv);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (r < 0) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen log_error("Failed to get unit property %s: %s", property, bus_error_message(&error, -r));
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek return r;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic int compare_unit_time(const void *a, const void *b) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return compare(((struct unit_times *)b)->time,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers ((struct unit_times *)a)->time);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers}
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversstatic int compare_unit_start(const void *a, const void *b) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return compare(((struct unit_times *)a)->activating,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen ((struct unit_times *)b)->activating);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversstatic int get_os_name(char **_n) {
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers char *n = NULL;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers int r;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering r = parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &n, NULL);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt if (r < 0)
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers return r;
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!n)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -ENOENT;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers *_n = n;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers return 0;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic void free_unit_times(struct unit_times *t, unsigned n) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen struct unit_times *p;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen for (p = t; p < t + n; p++)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering free(p->name);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering free(t);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int acquire_time_data(sd_bus *bus, struct unit_times **out) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int r, c = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct unit_times *unit_times = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t size = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering UnitInfo u;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = sd_bus_call_method(
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen bus,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "org.freedesktop.systemd1",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "/org/freedesktop/systemd1",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "org.freedesktop.systemd1.Manager",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "ListUnits",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen &error, &reply,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen NULL);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (r < 0) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen log_error("Failed to list units: %s", bus_error_message(&error, -r));
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen goto fail;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (r < 0) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen bus_log_parse_error(r);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen goto fail;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering while ((r = bus_parse_unit_info(reply, &u)) > 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct unit_times *t;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!GREEDY_REALLOC(unit_times, size, c+1)) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = log_oom();
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen goto fail;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t = unit_times+c;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t->name = NULL;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen assert_cc(sizeof(usec_t) == sizeof(uint64_t));
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (bus_get_uint64_property(bus, u.unit_path,
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John "org.freedesktop.systemd1.Unit",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "InactiveExitTimestampMonotonic",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen &t->activating) < 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus, u.unit_path,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "org.freedesktop.systemd1.Unit",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "ActiveEnterTimestampMonotonic",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen &t->activated) < 0 ||
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering bus_get_uint64_property(bus, u.unit_path,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "org.freedesktop.systemd1.Unit",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "ActiveExitTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering &t->deactivating) < 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus, u.unit_path,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "org.freedesktop.systemd1.Unit",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "InactiveEnterTimestampMonotonic",
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering &t->deactivated) < 0) {
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering r = -EIO;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto fail;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (t->activated >= t->activating)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t->time = t->activated - t->activating;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen else if (t->deactivated >= t->activating)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t->time = t->deactivated - t->activating;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen else
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t->time = 0;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (t->activating == 0)
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering continue;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t->name = strdup(u.id);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (t->name == NULL) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen r = log_oom();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto fail;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen c++;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering if (r < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_log_parse_error(r);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto fail;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering *out = unit_times;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return c;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poetteringfail:
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering free_unit_times(unit_times, (unsigned) c);
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering return r;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersenstatic int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen static struct boot_times times;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen static bool cached = false;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (cached)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen goto finish;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering assert_cc(sizeof(usec_t) == sizeof(uint64_t));
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (bus_get_uint64_property(bus,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "/org/freedesktop/systemd1",
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "FirmwareTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering &times.firmware_time) < 0 ||
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen bus_get_uint64_property(bus,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/org/freedesktop/systemd1",
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "LoaderTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering &times.loader_time) < 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/org/freedesktop/systemd1",
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering "org.freedesktop.systemd1.Manager",
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt "KernelTimestamp",
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt &times.kernel_time) < 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/org/freedesktop/systemd1",
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "InitRDTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering &times.initrd_time) < 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/org/freedesktop/systemd1",
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering "UserspaceTimestampMonotonic",
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering &times.userspace_time) < 0 ||
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John bus_get_uint64_property(bus,
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "/org/freedesktop/systemd1",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "FinishTimestampMonotonic",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek &times.finish_time) < 0 ||
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek bus_get_uint64_property(bus,
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "/org/freedesktop/systemd1",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "org.freedesktop.systemd1.Manager",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "SecurityStartTimestampMonotonic",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek &times.security_start_time) < 0 ||
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John bus_get_uint64_property(bus,
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John "/org/freedesktop/systemd1",
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek "org.freedesktop.systemd1.Manager",
3906ab4adf0aa7b952e39100262a11acd55cd79bRonny Chevalier "SecurityFinishTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering &times.security_finish_time) < 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/org/freedesktop/systemd1",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "GeneratorsStartTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering &times.generators_start_time) < 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/org/freedesktop/systemd1",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "org.freedesktop.systemd1.Manager",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "GeneratorsFinishTimestampMonotonic",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering &times.generators_finish_time) < 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bus_get_uint64_property(bus,
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/org/freedesktop/systemd1",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "org.freedesktop.systemd1.Manager",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "UnitsLoadStartTimestampMonotonic",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering &times.unitsload_start_time) < 0 ||
c978343015c787713651dff571acb5207367f5f2Lennart Poettering bus_get_uint64_property(bus,
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen "/org/freedesktop/systemd1",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "org.freedesktop.systemd1.Manager",
c978343015c787713651dff571acb5207367f5f2Lennart Poettering "UnitsLoadFinishTimestampMonotonic",
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering &times.unitsload_finish_time) < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -EIO;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (times.finish_time <= 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error("Bootup is not yet finished. Please try again later.");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -EINPROGRESS;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek if (times.initrd_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering times.kernel_done_time = times.initrd_time;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering else
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering times.kernel_done_time = times.userspace_time;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek cached = true;
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringfinish:
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering *bt = &times;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int pretty_boot_time(sd_bus *bus, char **_buf) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen char ts[FORMAT_TIMESPAN_MAX];
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen struct boot_times *t;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen static char buf[4096];
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t size;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char *ptr;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen int r;
de33fc625725d199629ed074d6278504deb23debLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen r = acquire_boot_times(bus, &t);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (r < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return r;
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen ptr = buf;
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen size = sizeof(buf);
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen
c978343015c787713651dff571acb5207367f5f2Lennart Poettering size = strpcpyf(&ptr, size, "Startup finished in ");
c978343015c787713651dff571acb5207367f5f2Lennart Poettering if (t->firmware_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (firmware) + ", format_timespan(ts, sizeof(ts), t->firmware_time - t->loader_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (t->loader_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (loader) + ", format_timespan(ts, sizeof(ts), t->loader_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (t->kernel_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (kernel) + ", format_timespan(ts, sizeof(ts), t->kernel_done_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (t->initrd_time > 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (initrd) + ", format_timespan(ts, sizeof(ts), t->userspace_time - t->initrd_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (t->kernel_time > 0)
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering else
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering ptr = strdup(buf);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!ptr)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return log_oom();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering *_buf = ptr;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic void svg_graph_box(double height, double begin, double end) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering long long i;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* outside box, fill */
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen svg("<rect class=\"box\" x=\"0\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * (end - begin), SCALE_Y * height);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering for (i = ((long long) (begin / 100000)) * 100000; i <= end; i+=100000) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* lines for each second */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (i % 5000000 == 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering else if (i % 1000000 == 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering else
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SCALE_X * i, SCALE_X * i, SCALE_Y * height);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int analyze_plot(sd_bus *bus) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct unit_times *times;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct boot_times *boot;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct utsname name;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int n, m = 1, y=0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering double width;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_free_ char *pretty_times = NULL, *osname = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct unit_times *u;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering n = acquire_boot_times(bus, &boot);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (n < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return n;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering n = pretty_boot_time(bus, &pretty_times);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (n < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return n;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering get_os_name(&osname);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert_se(uname(&name) >= 0);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering n = acquire_time_data(bus, &times);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (n <= 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return n;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering qsort(times, n, sizeof(struct unit_times), compare_unit_start);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering width = SCALE_X * (boot->firmware_time + boot->finish_time);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (width < 800.0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering width = 800.0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (boot->firmware_time > boot->loader_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering m++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (boot->loader_time) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering m++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (width < 1000.0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering width = 1000.0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (boot->initrd_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering m++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (boot->kernel_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering m++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering for (u = times; u < times + n; u++) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering double text_start, text_width;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (u->activating < boot->userspace_time ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering u->activating > boot->finish_time) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering free(u->name);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering u->name = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering continue;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
249968612f16a71df909d6e73785c18a9ff36a65Lennart Poettering /* If the text cannot fit on the left side then
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering * increase the svg width so it fits on the right.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * TODO: calculate the text width more accurately */
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner text_width = 8.0 * strlen(u->name);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering text_start = (boot->firmware_time + u->activating) * SCALE_X;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (text_width > text_start && text_width + text_start > width)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering width = text_width + text_start;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering if (u->deactivated > u->activating && u->deactivated <= boot->finish_time
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering && u->activated == 0 && u->deactivating == 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering u->activated = u->deactivating = u->deactivated;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (u->activated < u->activating || u->activated > boot->finish_time)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen u->activated = boot->finish_time;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt if (u->deactivating < u->activated || u->activated > boot->finish_time)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen u->deactivating = boot->finish_time;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (u->deactivated < u->deactivating || u->deactivated > boot->finish_time)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering u->deactivated = boot->finish_time;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen m++;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering svg("<?xml version=\"1.0\" standalone=\"no\"?>\n"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" "
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
svg("<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" "
"xmlns=\"http://www.w3.org/2000/svg\">\n\n",
80.0 + width, 150.0 + (m * SCALE_Y) +
5 * SCALE_Y /* legend */);
/* write some basic info as a comment, including some help */
svg("<!-- This file is a systemd-analyze SVG file. It is best rendered in a -->\n"
"<!-- browser such as Chrome, Chromium or Firefox. Other applications -->\n"
"<!-- that render these files properly but much slower are ImageMagick, -->\n"
"<!-- gimp, inkscape, etc. To display the files on your system, just -->\n"
"<!-- point your browser to this file. -->\n\n"
"<!-- This plot was generated by systemd-analyze version %-16.16s -->\n\n", VERSION);
/* style sheet */
svg("<defs>\n <style type=\"text/css\">\n <![CDATA[\n"
" rect { stroke-width: 1; stroke-opacity: 0; }\n"
" rect.background { fill: rgb(255,255,255); }\n"
" rect.activating { fill: rgb(255,0,0); fill-opacity: 0.7; }\n"
" rect.active { fill: rgb(200,150,150); fill-opacity: 0.7; }\n"
" rect.deactivating { fill: rgb(150,100,100); fill-opacity: 0.7; }\n"
" rect.kernel { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
" rect.initrd { fill: rgb(150,150,150); fill-opacity: 0.7; }\n"
" 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"
" line { stroke: rgb(64,64,64); stroke-width: 1; }\n"
"// line.sec1 { }\n"
" line.sec5 { stroke-width: 2; }\n"
" line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n"
" text { font-family: Verdana, Helvetica; font-size: 14px; }\n"
" text.left { font-family: Verdana, Helvetica; font-size: 14px; text-anchor: start; }\n"
" text.right { font-family: Verdana, Helvetica; font-size: 14px; text-anchor: end; }\n"
" text.sec { font-size: 10px; }\n"
" ]]>\n </style>\n</defs>\n\n");
svg("<rect class=\"background\" width=\"100%%\" height=\"100%%\" />\n");
svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times);
svg("<text x=\"20\" y=\"30\">%s %s (%s %s) %s</text>",
isempty(osname) ? "Linux" : osname,
name.nodename, name.release, name.version, name.machine);
svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time));
svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time);
if (boot->firmware_time) {
svg_bar("firmware", -(double) boot->firmware_time, -(double) boot->loader_time, y);
svg_text(true, -(double) boot->firmware_time, y, "firmware");
y++;
}
if (boot->loader_time) {
svg_bar("loader", -(double) boot->loader_time, 0, y);
svg_text(true, -(double) boot->loader_time, y, "loader");
y++;
}
if (boot->kernel_time) {
svg_bar("kernel", 0, boot->kernel_done_time, y);
svg_text(true, 0, y, "kernel");
y++;
}
if (boot->initrd_time) {
svg_bar("initrd", boot->initrd_time, boot->userspace_time, y);
svg_text(true, boot->initrd_time, y, "initrd");
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");
y++;
for (u = times; u < times + n; u++) {
char ts[FORMAT_TIMESPAN_MAX];
bool b;
if (!u->name)
continue;
svg_bar("activating", u->activating, u->activated, y);
svg_bar("active", u->activated, u->deactivating, y);
svg_bar("deactivating", u->deactivating, u->deactivated, y);
/* place the text on the left if we have passed the half of the svg width */
b = u->activating * SCALE_X < width / 2;
if (u->time)
svg_text(b, u->activating, y, "%s (%s)",
u->name, format_timespan(ts, sizeof(ts), u->time, USEC_PER_MSEC));
else
svg_text(b, u->activating, y, "%s", u->name);
y++;
}
svg("</g>\n");
/* Legend */
svg("<g transform=\"translate(20,100)\">\n");
y++;
svg_bar("activating", 0, 300000, y);
svg_text(true, 400000, y, "Activating");
y++;
svg_bar("active", 0, 300000, y);
svg_text(true, 400000, y, "Active");
y++;
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++;
svg_bar("unitsload", 0, 300000, y);
svg_text(true, 400000, y, "Loading unit files");
y++;
svg("</g>\n\n");
svg("</svg>\n");
free_unit_times(times, (unsigned) n);
return 0;
}
static int list_dependencies_print(const char *name, unsigned int level, unsigned int branches,
bool last, struct unit_times *times, struct boot_times *boot) {
unsigned int i;
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(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
if (times) {
if (times->time)
printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED_ON, name,
format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC),
format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF);
else if (times->activated > boot->userspace_time)
printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
else
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 = NULL;
assert(bus);
assert(name);
assert(deps);
path = unit_dbus_path_from_name(name);
if (path == NULL)
return -ENOMEM;
return bus_get_unit_property_strv(bus, path, "After", deps);
}
static Hashmap *unit_times_hashmap;
static int list_dependencies_compare(const void *_a, const void *_b) {
const char **a = (const char**) _a, **b = (const char**) _b;
usec_t usa = 0, usb = 0;
struct unit_times *times;
times = hashmap_get(unit_times_hashmap, *a);
if (times)
usa = times->activated;
times = hashmap_get(unit_times_hashmap, *b);
if (times)
usb = times->activated;
return usb - usa;
}
static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int level, char ***units,
unsigned int branches) {
_cleanup_strv_free_ char **deps = NULL;
char **c;
int r = 0;
usec_t service_longest = 0;
int to_print = 0;
struct unit_times *times;
struct boot_times *boot;
if (strv_extend(units, name))
return log_oom();
r = list_dependencies_get_dependencies(bus, name, &deps);
if (r < 0)
return r;
qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
r = acquire_boot_times(bus, &boot);
if (r < 0)
return r;
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
if (times
&& times->activated
&& times->activated <= boot->finish_time
&& (times->activated >= service_longest
|| service_longest == 0)) {
service_longest = times->activated;
break;
}
}
if (service_longest == 0 )
return r;
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
if (times && times->activated
&& times->activated <= boot->finish_time
&& (service_longest - times->activated) <= arg_fuzz) {
to_print++;
}
}
if (!to_print)
return r;
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
if (!times
|| !times->activated
|| times->activated > boot->finish_time
|| service_longest - times->activated > arg_fuzz)
continue;
to_print--;
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 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"
" --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\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",
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[]) {
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
};
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 },
{ "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':
return help();
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 '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
}
return 1;
}
int main(int argc, char *argv[]) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
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;
r = bus_open_transport(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;
}