summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2022-08-02 20:15:12 +0100
committerLuca Boccassi <bluca@debian.org>2022-08-23 21:19:54 +0100
commitc8bc7519c888a99134f88f8c82353246d3c0cc5d (patch)
treea7733a97f5c2487dc1998c8a2f3e88b30caca187
parent4c420328549ed98c6ca170d8ccc89cbee2f38ccc (diff)
downloadsystemd-c8bc7519c888a99134f88f8c82353246d3c0cc5d.tar.gz
service: set TRIGGER_UNIT= and TRIGGER_TIMER_REALTIME_USEC/MONOTONIC_USEC on activation by timer unit
Same as path unit, best effort.
-rw-r--r--man/systemd.exec.xml4
-rw-r--r--man/systemd.timer.xml4
-rw-r--r--src/core/timer.c107
-rw-r--r--src/core/timer.h8
-rw-r--r--src/core/unit.c1
-rwxr-xr-xtest/units/testsuite-07.sh3
6 files changed, 125 insertions, 2 deletions
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 2acb737c38..2e843be2e5 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -3698,8 +3698,10 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
<varlistentry>
<term><varname>$TRIGGER_UNIT</varname></term>
<term><varname>$TRIGGER_PATH</varname></term>
+ <term><varname>$TRIGGER_TIMER_REALTIME_USEC</varname></term>
+ <term><varname>$TRIGGER_TIMER_MONOTONIC_USEC</varname></term>
- <listitem><para>If the unit was activated dynamically (e.g.: a corresponding path unit), the
+ <listitem><para>If the unit was activated dynamically (e.g.: a corresponding path unit or timer unit), the
unit that triggered it and other type-dependent information will be passed via these variables. Note that
this information is provided in a best-effort way. For example, multiple triggers happening one after
another will be coalesced and only one will be reported, with no guarantee as to which one it will be.
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index 49bcb18be5..953faa9b33 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -366,6 +366,10 @@
<refsect1>
<title>See Also</title>
+ <para>Environment variables with details on the trigger will be set for triggered units. See the
+ <literal>Environment Variables Set on Triggered Units</literal> section in
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for more details.</para>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
diff --git a/src/core/timer.c b/src/core/timer.c
index 9de325ba66..b89d593b75 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -576,8 +576,10 @@ fail:
}
static void timer_enter_running(Timer *t) {
+ _cleanup_(activation_details_unrefp) ActivationDetails *details = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
Unit *trigger;
+ Job *job;
int r;
assert(t);
@@ -593,11 +595,20 @@ static void timer_enter_running(Timer *t) {
return;
}
- r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
+ details = activation_details_new(UNIT(t));
+ if (!details) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, &job);
if (r < 0)
goto fail;
dual_timestamp_get(&t->last_trigger);
+ ACTIVATION_DETAILS_TIMER(details)->last_trigger = t->last_trigger;
+
+ job_set_activation_details(job, details);
if (t->stamp_path)
touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
@@ -892,6 +903,91 @@ static int timer_can_start(Unit *u) {
return 1;
}
+static void activation_details_timer_serialize(ActivationDetails *details, FILE *f) {
+ ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+
+ assert(details);
+ assert(f);
+ assert(t);
+
+ (void) serialize_dual_timestamp(f, "activation-details-timer-last-trigger", &t->last_trigger);
+}
+
+static int activation_details_timer_deserialize(const char *key, const char *value, ActivationDetails **details) {
+ int r;
+
+ assert(key);
+ assert(value);
+
+ if (!details || !*details)
+ return -EINVAL;
+
+ ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(*details);
+ if (!t)
+ return -EINVAL;
+
+ if (!streq(key, "activation-details-timer-last-trigger"))
+ return -EINVAL;
+
+ r = deserialize_dual_timestamp(value, &t->last_trigger);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int activation_details_timer_append_env(ActivationDetails *details, char ***strv) {
+ ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+ int r;
+
+ assert(details);
+ assert(strv);
+ assert(t);
+
+ if (!dual_timestamp_is_set(&t->last_trigger))
+ return 0;
+
+ r = strv_extendf(strv, "TRIGGER_TIMER_REALTIME_USEC=%" USEC_FMT, t->last_trigger.realtime);
+ if (r < 0)
+ return r;
+
+ r = strv_extendf(strv, "TRIGGER_TIMER_MONOTONIC_USEC=%" USEC_FMT, t->last_trigger.monotonic);
+ if (r < 0)
+ return r;
+
+ return 2; /* Return the number of variables added to the env block */
+}
+
+static int activation_details_timer_append_pair(ActivationDetails *details, char ***strv) {
+ ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+ int r;
+
+ assert(details);
+ assert(strv);
+ assert(t);
+
+ if (!dual_timestamp_is_set(&t->last_trigger))
+ return 0;
+
+ r = strv_extend(strv, "trigger_timer_realtime_usec");
+ if (r < 0)
+ return r;
+
+ r = strv_extendf(strv, "%" USEC_FMT, t->last_trigger.realtime);
+ if (r < 0)
+ return r;
+
+ r = strv_extend(strv, "trigger_timer_monotonic_usec");
+ if (r < 0)
+ return r;
+
+ r = strv_extendf(strv, "%" USEC_FMT, t->last_trigger.monotonic);
+ if (r < 0)
+ return r;
+
+ return 2; /* Return the number of pairs added to the env block */
+}
+
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
[TIMER_ACTIVE] = "OnActiveSec",
[TIMER_BOOT] = "OnBootSec",
@@ -954,3 +1050,12 @@ const UnitVTable timer_vtable = {
.can_start = timer_can_start,
};
+
+const ActivationDetailsVTable activation_details_timer_vtable = {
+ .object_size = sizeof(ActivationDetailsTimer),
+
+ .serialize = activation_details_timer_serialize,
+ .deserialize = activation_details_timer_deserialize,
+ .append_env = activation_details_timer_append_env,
+ .append_pair = activation_details_timer_append_pair,
+};
diff --git a/src/core/timer.h b/src/core/timer.h
index 551e283341..914e42580e 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -2,6 +2,7 @@
#pragma once
typedef struct Timer Timer;
+typedef struct ActivationDetailsTimer ActivationDetailsTimer;
#include "calendarspec.h"
#include "unit.h"
@@ -64,11 +65,17 @@ struct Timer {
char *stamp_path;
};
+struct ActivationDetailsTimer {
+ ActivationDetails meta;
+ dual_timestamp last_trigger;
+};
+
#define TIMER_MONOTONIC_CLOCK(t) ((t)->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC)
void timer_free_values(Timer *t);
extern const UnitVTable timer_vtable;
+extern const ActivationDetailsVTable activation_details_timer_vtable;
const char *timer_base_to_string(TimerBase i) _const_;
TimerBase timer_base_from_string(const char *s) _pure_;
@@ -77,3 +84,4 @@ const char* timer_result_to_string(TimerResult i) _const_;
TimerResult timer_result_from_string(const char *s) _pure_;
DEFINE_CAST(TIMER, Timer);
+DEFINE_ACTIVATION_DETAILS_CAST(ACTIVATION_DETAILS_TIMER, ActivationDetailsTimer, TIMER);
diff --git a/src/core/unit.c b/src/core/unit.c
index 4255e0cf1f..5f1c6109b0 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -5931,6 +5931,7 @@ int unit_get_dependency_array(const Unit *u, UnitDependencyAtom atom, Unit ***re
const ActivationDetailsVTable * const activation_details_vtable[_UNIT_TYPE_MAX] = {
[UNIT_PATH] = &activation_details_path_vtable,
+ [UNIT_TIMER] = &activation_details_timer_vtable,
};
ActivationDetails *activation_details_new(Unit *trigger_unit) {
diff --git a/test/units/testsuite-07.sh b/test/units/testsuite-07.sh
index 5e9fe64ea9..95ebe3876f 100755
--- a/test/units/testsuite-07.sh
+++ b/test/units/testsuite-07.sh
@@ -8,6 +8,9 @@ set -o pipefail
cat >/lib/systemd/system/my.service <<EOF
[Service]
Type=oneshot
+ExecStartPre=sh -c 'test "\$TRIGGER_UNIT" = my.timer'
+ExecStartPre=sh -c 'test -n "\$TRIGGER_TIMER_REALTIME_USEC"'
+ExecStartPre=sh -c 'test -n "\$TRIGGER_TIMER_MONOTONIC_USEC"'
ExecStart=/bin/echo Timer runs me
EOF