analyze: add new "calendar" command

This little new command can parse, validate, normalize calendar events,
and calculate when they will elapse next. This should be useful for
anyone writing calendar events and who'd like to validate the expression
before running them as timer units.
This commit is contained in:
Lennart Poettering 2017-11-17 10:33:22 +01:00
parent 9a9a4f10e9
commit 6d86f4bd11
4 changed files with 88 additions and 1 deletions

View File

@ -125,6 +125,12 @@
<arg choice="plain">verify</arg>
<arg choice="opt" rep="repeat"><replaceable>FILES</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">calendar</arg>
<arg choice="plain" rep="repeat"><replaceable>SPECS</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@ -220,6 +226,12 @@
All units files present in the directories containing the command line arguments will
be used in preference to the other paths.</para>
<para><command>systemd-analyze calendar</command> will parse and normalize repetitive calendar time events, and
will calculate when they will elapse next. This takes the same input as the <varname>OnCalendar=</varname> setting
in <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>, following the
syntax described in
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
<para>If no command is passed, <command>systemd-analyze
time</command> is implied.</para>

View File

@ -302,6 +302,10 @@ Wed..Sat,Tue 12-10-15 1:2:3 → Tue..Sat 2012-10-15 01:02:03
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para>
<para>Use the <command>calendar</command> command of
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry> to validate
and normalize calendar time specifications for testing purposes. The tool also calculates when a specified
calendar event would elapse next.</para>
</refsect1>
<refsect1>
@ -311,7 +315,8 @@ Wed..Sat,Tue 12-10-15 1:2:3 → Tue..Sat 2012-10-15 01:02:03
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>

View File

@ -31,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"
@ -1395,6 +1396,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);
@ -1429,6 +1494,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
@ -1618,6 +1684,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]);
}

View File

@ -61,3 +61,5 @@ int calendar_spec_to_string(const CalendarSpec *spec, char **p);
int calendar_spec_from_string(const char *p, CalendarSpec **spec);
int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next);
DEFINE_TRIVIAL_CLEANUP_FUNC(CalendarSpec*, calendar_spec_free);