service: set TRIGGER_UNIT= and TRIGGER_TIMER_REALTIME_USEC/MONOTONIC_USEC on activation by timer unit

Same as path unit, best effort.
This commit is contained in:
Luca Boccassi
2022-08-23 21:19:54 +01:00
parent 4c42032854
commit c8bc7519c8
6 changed files with 125 additions and 2 deletions
+3 -1
View File
@@ -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.
+4
View File
@@ -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>,
+106 -1
View File
@@ -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,
};
+8
View File
@@ -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);
+1
View File
@@ -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) {
+3
View File
@@ -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