From f2ccf8320ac5d121cc8f50622ae3c9af1d0bfea2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Feb 2019 12:07:05 +0100 Subject: [PATCH] analyze: optionally, show more than one elapse time for calendar expressions --- man/systemd-analyze.xml | 20 ++++++++++++----- src/analyze/analyze.c | 50 +++++++++++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 7becf0133e9..774449d5a00 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -251,11 +251,14 @@ NAutoVTs=8 All units files present in the directories containing the command line arguments will be used in preference to the other paths. - systemd-analyze calendar will parse and normalize repetitive calendar time events, and - will calculate when they will elapse next. This takes the same input as the OnCalendar= setting - in systemd.timer5, following the - syntax described in - systemd.time7. + systemd-analyze calendar will parse and normalize repetitive calendar time + events, and will calculate when they will elapse next. This takes the same input as the + OnCalendar= setting in + systemd.timer5, + following the syntax described in + systemd.time7. By + default, only the next time the calendar expression will elapse is shown; use + to show the specified number of next times the expression elapses. systemd-analyze service-watchdogs prints the current state of service runtime watchdogs of the systemd daemon. @@ -401,6 +404,13 @@ NAutoVTs=8 the specified root path PATH. + + + + When used with the calendar command, show the specified number of + iterations the specified calendar expression will elapse next. Defaults to 1. + + diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 6fa6ef93cce..064525d64d3 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -78,6 +78,7 @@ static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; static bool arg_man = true; static bool arg_generators = false; static const char *arg_root = NULL; +static unsigned arg_iterations = 1; STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep); @@ -1680,7 +1681,7 @@ static int test_calendar(int argc, char *argv[], void *userdata) { STRV_FOREACH(p, strv_skip(argv, 1)) { _cleanup_(calendar_spec_freep) CalendarSpec *spec = NULL; _cleanup_free_ char *t = NULL; - usec_t next; + unsigned i; r = calendar_spec_from_string(*p, &spec); if (r < 0) { @@ -1705,21 +1706,42 @@ static int test_calendar(int argc, char *argv[], void *userdata) { 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 { + for (i = 0; i < arg_iterations; i++) { char buffer[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESTAMP_RELATIVE_MAX)]; + usec_t next; - printf(" Next elapse: %s\n", format_timestamp(buffer, sizeof(buffer), next)); + r = calendar_spec_next_usec(spec, n, &next); + if (r == -ENOENT) { + if (i > 0) + break; + + printf(" Next elapse: never\n"); + return ret; + } + if (r < 0) { + ret = log_error_errno(r, "Failed to determine next elapse for '%s': %m", *p); + break; + } + + if (i == 0) + printf(" Next elapse: %s\n", format_timestamp(buffer, sizeof(buffer), next)); + else { + int k = DECIMAL_STR_WIDTH(i+1); + + if (k < 8) + k = 8 - k; + else + k = 0; + + printf("%*sIter. #%u: %s\n", k, "", i+1, 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)); + + n = next; } if (*(p+1)) @@ -1827,6 +1849,7 @@ static int help(int argc, char *argv[], void *userdata) { " earlier than the latest in the branch\n" " --man[=BOOL] Do [not] check for existence of man pages\n" " --generators[=BOOL] Do [not] run unit generators (requires privileges)\n" + " --iterations=N Show the specified number of iterations\n" "\nCommands:\n" " time Print time spent in the kernel\n" " blame Print list of running units ordered by time to init\n" @@ -1870,6 +1893,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_NO_PAGER, ARG_MAN, ARG_GENERATORS, + ARG_ITERATIONS, }; static const struct option options[] = { @@ -1889,6 +1913,7 @@ static int parse_argv(int argc, char *argv[]) { { "generators", optional_argument, NULL, ARG_GENERATORS }, { "host", required_argument, NULL, 'H' }, { "machine", required_argument, NULL, 'M' }, + { "iterations", required_argument, NULL, ARG_ITERATIONS }, {} }; @@ -1988,6 +2013,13 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_ITERATIONS: + r = safe_atou(optarg, &arg_iterations); + if (r < 0) + return log_error_errno(r, "Failed to parse iterations: %s", optarg); + + break; + case '?': return -EINVAL;