1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-09-16 17:45:52 +03:00

Merge pull request #7373 from poettering/analyze-calendar

add nifty little "systemd-analyze calendar" command
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2017-11-20 11:25:55 +01:00
committed by GitHub
10 changed files with 123 additions and 7 deletions

4
TODO
View File

@@ -28,6 +28,10 @@ Features:
the runtime dir as we maintain for the fdstore: i.e. keep it around as long the runtime dir as we maintain for the fdstore: i.e. keep it around as long
as the unit is running or has a job queued. as the unit is running or has a job queued.
* hook up sd-bus' creds stuff with SO_PEERGROUPS
* add async version of sd_bus_add_match and make use of that
* let's log the "tainted" string at boot * let's log the "tainted" string at boot
* Add NetworkNamespacePath= to specify a path to a network namespace * Add NetworkNamespacePath= to specify a path to a network namespace

View File

@@ -125,6 +125,12 @@
<arg choice="plain">verify</arg> <arg choice="plain">verify</arg>
<arg choice="opt" rep="repeat"><replaceable>FILES</replaceable></arg> <arg choice="opt" rep="repeat"><replaceable>FILES</replaceable></arg>
</cmdsynopsis> </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> </refsynopsisdiv>
<refsect1> <refsect1>
@@ -220,6 +226,12 @@
All units files present in the directories containing the command line arguments will All units files present in the directories containing the command line arguments will
be used in preference to the other paths.</para> 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 <para>If no command is passed, <command>systemd-analyze
time</command> is implied.</para> 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> <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para> 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>
<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>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.unit</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> </para>
</refsect1> </refsect1>

View File

@@ -31,6 +31,7 @@
#include "bus-error.h" #include "bus-error.h"
#include "bus-unit-util.h" #include "bus-unit-util.h"
#include "bus-util.h" #include "bus-util.h"
#include "calendarspec.h"
#include "glob-util.h" #include "glob-util.h"
#include "hashmap.h" #include "hashmap.h"
#include "locale-util.h" #include "locale-util.h"
@@ -1395,6 +1396,70 @@ static int dump_syscall_filters(char** names) {
} }
#endif #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) { static void help(void) {
pager_open(arg_no_pager, false); pager_open(arg_no_pager, false);
@@ -1429,6 +1494,7 @@ static void help(void) {
" dump Output state serialization of service manager\n" " dump Output state serialization of service manager\n"
" syscall-filter [NAME...] Print list of syscalls in seccomp filter\n" " syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
" verify FILE... Check unit files for correctness\n" " verify FILE... Check unit files for correctness\n"
" calendar SPEC... Validate repetitive calendar time events\n"
, program_invocation_short_name); , program_invocation_short_name);
/* When updating this list, including descriptions, apply /* 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); r = get_log_target(bus, argv+optind+1);
else if (streq(argv[optind], "syscall-filter")) else if (streq(argv[optind], "syscall-filter"))
r = dump_syscall_filters(argv+optind+1); r = dump_syscall_filters(argv+optind+1);
else if (streq(argv[optind], "calendar"))
r = test_calendar(argv+optind+1);
else else
log_error("Unknown operation '%s'.", argv[optind]); log_error("Unknown operation '%s'.", argv[optind]);
} }

View File

@@ -51,10 +51,10 @@ static void free_chain(CalendarComponent *c) {
} }
} }
void calendar_spec_free(CalendarSpec *c) { CalendarSpec* calendar_spec_free(CalendarSpec *c) {
if (!c) if (!c)
return; return NULL;
free_chain(c->year); free_chain(c->year);
free_chain(c->month); free_chain(c->month);
@@ -64,7 +64,7 @@ void calendar_spec_free(CalendarSpec *c) {
free_chain(c->microsecond); free_chain(c->microsecond);
free(c->timezone); free(c->timezone);
free(c); return mfree(c);
} }
static int component_compare(const void *_a, const void *_b) { static int component_compare(const void *_a, const void *_b) {

View File

@@ -52,7 +52,7 @@ typedef struct CalendarSpec {
CalendarComponent *microsecond; CalendarComponent *microsecond;
} CalendarSpec; } CalendarSpec;
void calendar_spec_free(CalendarSpec *c); CalendarSpec* calendar_spec_free(CalendarSpec *c);
int calendar_spec_normalize(CalendarSpec *spec); int calendar_spec_normalize(CalendarSpec *spec);
bool calendar_spec_valid(CalendarSpec *spec); bool calendar_spec_valid(CalendarSpec *spec);
@@ -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_from_string(const char *p, CalendarSpec **spec);
int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next); int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next);
DEFINE_TRIVIAL_CLEANUP_FUNC(CalendarSpec*, calendar_spec_free);

View File

@@ -1457,3 +1457,9 @@ usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
/* x lies in the past */ /* x lies in the past */
return usec_sub_unsigned(b, usec_sub_unsigned(a, x)); return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
} }
bool in_utc_timezone(void) {
tzset();
return timezone == 0 && daylight == 0;
}

View File

@@ -156,6 +156,8 @@ struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
unsigned long usec_to_jiffies(usec_t usec); unsigned long usec_to_jiffies(usec_t usec);
bool in_utc_timezone(void);
static inline usec_t usec_add(usec_t a, usec_t b) { static inline usec_t usec_add(usec_t a, usec_t b) {
usec_t c; usec_t c;

View File

@@ -1084,7 +1084,7 @@ static int get_next_elapse(
't', 't',
&t.monotonic); &t.monotonic);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r)); return log_error_errno(r, "Failed to get next elapse time: %s", bus_error_message(&error, r));
r = sd_bus_get_property_trivial( r = sd_bus_get_property_trivial(
bus, bus,
@@ -1096,7 +1096,7 @@ static int get_next_elapse(
't', 't',
&t.realtime); &t.realtime);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r)); return log_error_errno(r, "Failed to get next elapse time: %s", bus_error_message(&error, r));
*next = t; *next = t;
return 0; return 0;

View File

@@ -383,6 +383,22 @@ static void test_usec_shift_clock(void) {
} }
} }
static void test_in_utc_timezone(void) {
assert_se(setenv("TZ", ":UTC", 1) >= 0);
assert_se(in_utc_timezone());
assert_se(streq(tzname[0], "UTC"));
assert_se(streq(tzname[1], "UTC"));
assert_se(timezone == 0);
assert_se(daylight == 0);
assert_se(setenv("TZ", "Europe/Berlin", 1) >= 0);
assert_se(!in_utc_timezone());
assert_se(streq(tzname[0], "CET"));
assert_se(streq(tzname[1], "CEST"));
assert_se(unsetenv("TZ") >= 0);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
uintmax_t x; uintmax_t x;
@@ -409,6 +425,7 @@ int main(int argc, char *argv[]) {
test_format_timestamp_utc(); test_format_timestamp_utc();
test_dual_timestamp_deserialize(); test_dual_timestamp_deserialize();
test_usec_shift_clock(); test_usec_shift_clock();
test_in_utc_timezone();
/* Ensure time_t is signed */ /* Ensure time_t is signed */
assert_cc((time_t) -1 < (time_t) 1); assert_cc((time_t) -1 < (time_t) 1);