summaryrefslogtreecommitdiff
path: root/src/analyze/analyze.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/analyze/analyze.c')
-rw-r--r--src/analyze/analyze.c109
1 files changed, 105 insertions, 4 deletions
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 9fcc20dba3..d45c1dc496 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -30,6 +31,7 @@
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
+#include "calendarspec.h"
#include "glob-util.h"
#include "hashmap.h"
#include "locale-util.h"
@@ -414,7 +416,7 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
continue;
t->name = strdup(u.id);
- if (t->name == NULL) {
+ if (!t->name) {
r = log_oom();
goto fail;
}
@@ -489,11 +491,40 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
size_t size;
char *ptr;
int r;
+ usec_t activated_time = USEC_INFINITY;
+ _cleanup_free_ char* path = NULL, *unit_id = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = acquire_boot_times(bus, &t);
if (r < 0)
return r;
+ path = unit_dbus_path_from_name(SPECIAL_DEFAULT_TARGET);
+ if (!path)
+ return log_oom();
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.systemd1.Unit",
+ "Id",
+ &error,
+ &unit_id);
+ if (r < 0) {
+ log_error_errno(r, "default.target doesn't seem to exist: %s", bus_error_message(&error, r));
+ unit_id = NULL;
+ }
+
+ r = bus_get_uint64_property(bus, path,
+ "org.freedesktop.systemd1.Unit",
+ "ActiveEnterTimestampMonotonic",
+ &activated_time);
+ if (r < 0) {
+ log_info_errno(r, "default.target seems not to be started. Continuing...");
+ activated_time = USEC_INFINITY;
+ }
+
ptr = buf;
size = sizeof(buf);
@@ -510,6 +541,9 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
size = strpcpyf(&ptr, size, "%s (userspace) ", format_timespan(ts, sizeof(ts), t->finish_time - t->userspace_time, USEC_PER_MSEC));
strpcpyf(&ptr, size, "= %s", format_timespan(ts, sizeof(ts), t->firmware_time + t->finish_time, USEC_PER_MSEC));
+ if (unit_id && activated_time != USEC_INFINITY)
+ size = strpcpyf(&ptr, size, "\n%s reached after %s in userspace", unit_id, format_timespan(ts, sizeof(ts), activated_time - t->userspace_time, USEC_PER_MSEC));
+
ptr = strdup(buf);
if (!ptr)
return log_oom();
@@ -786,7 +820,7 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
assert(deps);
path = unit_dbus_path_from_name(name);
- if (path == NULL)
+ if (!path)
return -ENOMEM;
return bus_get_unit_property_strv(bus, path, "After", deps);
@@ -844,7 +878,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int lev
}
}
- if (service_longest == 0 )
+ if (service_longest == 0)
return r;
STRV_FOREACH(c, deps) {
@@ -903,7 +937,7 @@ static int list_dependencies(sd_bus *bus, const char *name) {
assert(bus);
path = unit_dbus_path_from_name(name);
- if (path == NULL)
+ if (!path)
return -ENOMEM;
r = sd_bus_get_property(
@@ -1394,6 +1428,70 @@ static int dump_syscall_filters(char** names) {
}
#endif
+static int test_calendar(char **args) {
+ int ret = 0, r;
+ char **p;
+ usec_t n;
+
+ if (strv_isempty(args)) {
+ log_error("Expected at least one calendar specification string as argument.");
+ return -EINVAL;
+ }
+
+ n = now(CLOCK_REALTIME);
+
+ STRV_FOREACH(p, args) {
+ _cleanup_(calendar_spec_freep) CalendarSpec *spec = NULL;
+ _cleanup_free_ char *t = NULL;
+ usec_t next;
+
+ r = calendar_spec_from_string(*p, &spec);
+ if (r < 0) {
+ ret = log_error_errno(r, "Failed to parse calendar specification '%s': %m", *p);
+ continue;
+ }
+
+ r = calendar_spec_normalize(spec);
+ if (r < 0) {
+ ret = log_error_errno(r, "Failed to normalize calendar specification '%s': %m", *p);
+ continue;
+ }
+
+ r = calendar_spec_to_string(spec, &t);
+ if (r < 0) {
+ ret = log_error_errno(r, "Failed to fomat calendar specification '%s': %m", *p);
+ continue;
+ }
+
+ if (!streq(t, *p))
+ printf(" Original form: %s\n", *p);
+
+ printf("Normalized form: %s\n", t);
+
+ r = calendar_spec_next_usec(spec, n, &next);
+ if (r == -ENOENT)
+ printf(" Next elapse: never\n");
+ else if (r < 0) {
+ ret = log_error_errno(r, "Failed to determine next elapse for '%s': %m", *p);
+ continue;
+ } else {
+ char buffer[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESTAMP_RELATIVE_MAX)];
+
+ printf(" Next elapse: %s\n", format_timestamp(buffer, sizeof(buffer), next));
+
+ if (!in_utc_timezone())
+ printf(" (in UTC): %s\n", format_timestamp_utc(buffer, sizeof(buffer), next));
+
+ printf(" From now: %s\n", format_timestamp_relative(buffer, sizeof(buffer), next));
+ }
+
+ if (*(p+1))
+ putchar('\n');
+ }
+
+ return ret;
+}
+
static void help(void) {
pager_open(arg_no_pager, false);
@@ -1428,6 +1526,7 @@ static void help(void) {
" dump Output state serialization of service manager\n"
" syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
" verify FILE... Check unit files for correctness\n"
+ " calendar SPEC... Validate repetitive calendar time events\n"
, program_invocation_short_name);
/* When updating this list, including descriptions, apply
@@ -1617,6 +1716,8 @@ int main(int argc, char *argv[]) {
r = get_log_target(bus, argv+optind+1);
else if (streq(argv[optind], "syscall-filter"))
r = dump_syscall_filters(argv+optind+1);
+ else if (streq(argv[optind], "calendar"))
+ r = test_calendar(argv+optind+1);
else
log_error("Unknown operation '%s'.", argv[optind]);
}