]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
analyze: add new "calendar" command
authorLennart Poettering <lennart@poettering.net>
Fri, 17 Nov 2017 09:33:22 +0000 (10:33 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 20 Nov 2017 09:57:41 +0000 (10:57 +0100)
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.

man/systemd-analyze.xml
man/systemd.time.xml
src/analyze/analyze.c
src/basic/calendarspec.h

index 956790c50c01a94a5d04b951fec91f8dcb15770a..876f96d5592610a3b422fbf51f94c737478c5b85 100644 (file)
       <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>
     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>
 
index a2fff2d101513643f9f1981bcc5666b866e7ed7b..6cb32f13b7c3ad3f7bdd15f9d2a4eea6fa9453fc 100644 (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>
 
index 913aa3501614c50128e5e71a485f213daf2abaae..5229b3a082f1735c9d8448013bb118b2bd5c1b7b 100644 (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]);
         }
index d2a19dd7ddc2722ddca3186983bdd7e4809fc630..124f7f5880e4dbafd4de708d14f7a962bae848cb 100644 (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);