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-02 20:15:12 +01:00
parent 4c42032854
commit c8bc7519c8
6 changed files with 125 additions and 2 deletions

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.

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>,

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,
};

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);

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) {

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