1
0
mirror of https://github.com/systemd/systemd synced 2025-11-21 01:34:44 +01:00

Compare commits

..

24 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
67a1069b72 meson: bump version to 258.1 2025-10-13 17:01:55 +02:00
Zbigniew Jędrzejewski-Szmek
377aaf6a27 hwdb: update to main@{2025-10-13}
git restore -s origin/main hwdb.d/ test/hwdb.d && git checkout hwdb.d/meson.build

This primarily reverts some changes made in the previous update.
2025-10-13 16:59:58 +02:00
Daan De Meyer
89950fc6a7 sd-id128: Drop _sd_const_ from sd_id128_in_setv()
Both the const and pure attributes disallow modifying input arguments
but sd_id128_in_setv() clearly modifies its ap input argument by iterating
over it with va_arg() so drop the _sd_const_ attribute from
sd_id128_in_setv().

(cherry picked from commit 675fa49f69943b0f009c973ed3d1e90afc1d88b1)
2025-10-13 16:59:40 +02:00
Lukas Nykryn
c058ff41cb timer: don't run service immediately after restart of a timer
When a timer is restarted, don't reset the last_trigger field.
This prevents the timer from triggering immediately.

Fixes: #31231
(cherry picked from commit 3fc44a0f68412b649e16f12ff2f97a36c615457d)
2025-10-13 16:59:40 +02:00
Frantisek Sumsal
469c22f72d test: check the next elapse timer timestamp after deserialization
When deserializing a serialized timer unit with RandomizedDelaySec= set,
systemd should use the last inactive exit timestamp instead of current
realtime to calculate the new next elapse, so the timer unit actually
runs in the given calendar window.

Provides coverage for:
  - https://github.com/systemd/systemd/issues/18678
  - https://github.com/systemd/systemd/pull/27752

(cherry picked from commit f4c3c107d9be4e922a080fc292ed3889c4e0f4a5)
2025-10-13 16:59:40 +02:00
Frantisek Sumsal
11df9345d3 test: restarting elapsed timer shouldn't trigger the corresponding service
Provides coverage for:
  - https://github.com/systemd/systemd/issues/31231
  - https://github.com/systemd/systemd/issues/35805

(cherry picked from commit 5730a400fd5ee82566fe03eb832121a0d4bc26b6)
2025-10-13 16:59:40 +02:00
Frantisek Sumsal
5036c8f58b test: rename TEST-53-ISSUE-16347 to TEST-53-TIMER
And split the existing test into a separate subtest.

(cherry picked from commit 953c347fb6f293acbd6da009646bfc071b68ddd7)
2025-10-13 16:59:40 +02:00
Luca Boccassi
e76c73505b sysext: do not attempt to unlock images interactively
These images are not using a passphrase, they are using keys
or at most TPM-based sealing (not yet implemented, for contexts).

Do not use the interactive helper, as it will block and ask the
user for a password if it fails to find the signing cert, which
is not useful for this tool.

Fixes https://github.com/systemd/systemd/issues/33179

(cherry picked from commit 09f655ad4af59ef4ff8ebd02ca5421f8901cb16b)
2025-10-13 16:59:40 +02:00
Luca Boccassi
49b7015314 meson: fix link-udev-shared option
This doesn't work anymore, setting it to false still makes
udev link to libsystemd-shared, as an argument was mistakenly
dropped.

Follow-up for 6350d2dbd97746440b9c8303ddc140ffda568732

(cherry picked from commit 9736f634c8b61343be966114ce1c9eddaf0fa742)
2025-10-13 16:59:40 +02:00
Kai Wohlfahrt
437a881f94 Fix path in docs for local pcrlock.d directory
(cherry picked from commit 9ba0fd9293b3be88d64199119f257b13a21caf67)
2025-10-13 16:59:40 +02:00
Lennart Poettering
897018cc47 mountfsd: uncomment CapabilityBoundingSet= line
Since mountfsd was added in 702a52f4b5d49cce11e2adbc740deb3b644e2de0 the
caps bounding set line was commented. That's an accident. Fix that. (We
need to add a bunch of caps to the list).

(cherry picked from commit 818bd1dfa1e4ac222b1fc5d238807e49fd1d7939)
2025-10-13 16:59:40 +02:00
Lennart Poettering
ba809a8584 core: fix status output suppression
This fixes two things: first of all it ensures we take the override
status output field properly into account, instead of going directly to
the regular one.

Moreover, it ensures that we bypass auto for both notice + emergency,
since both have the same "impact", and, don't limit this for notice
only.

(cherry picked from commit 9ecc969855ce7d8e587ea2ea0b6c3120877a7887)
2025-10-13 16:59:40 +02:00
Lennart Poettering
f3c0428c39 unit: line-break overly long parameter list + add assert()
(cherry picked from commit 8e9b722b4ad94d1739810ff2792b9c03ba5c850e)
2025-10-13 16:59:40 +02:00
Lennart Poettering
e9ca92bd74 job: shorten code
(cherry picked from commit 84ba8721de9d70340747758f9d028a3f9c4e302e)
2025-10-13 16:59:40 +02:00
Mike Yuan
0d48c2b4ee core/manager: honor show_status_overridden in manager_watch_jobs_next_time()
Prompted by #39029

(cherry picked from commit 4f8c1de21317818b8968f065435a2afb7cadf645)
2025-10-13 16:59:40 +02:00
Yu Watanabe
2ebc1de3fb machine: fix crash on update from older than v258
UID entry in the machine state file is introduced in v258,
hence when a host is upgraded to v258, the field does not exist in the
file, thus the variable 'uid' is NULL.

Follow-up for 276d20018623ef14956ce87975be48da5de63f29.
Fixes #39061.

(cherry picked from commit 43cea09f95e5a051432e040c823e945b8b327ed4)
2025-10-13 16:59:40 +02:00
Yu Watanabe
87bbee1c96 core/bpf-firewall: replace unnecessary unit_setup_cgroup_runtime() with unit_get_cgroup_runtime()
Except for the test, bpf_firewall_compile() is only called by the following:
  cgroup_context_apply() -> cgroup_apply_firewall() -> bpf_firewall_compile()
and in the early stage of cgroup_context_apply(), it checks if the cgroup
runtime exists. Hence, it is not necessary to try to allocate the
runtime in bpf_firewall_compile().

(cherry picked from commit e8a5cda4714fc6fe622a03cfca6c75888d63e354)
2025-10-13 16:59:40 +02:00
Mike Yuan
d8b74adbff core/cgroup: make sure deserialized accounting data is not voided
Currently, cgroup_path is (de-)serialized after all the cached
accounting data. This is bogus though, since unit_set_cgroup_path()
destroys the CGroupRuntime object and starts afresh, discarding
all deserialized values. This matters especially for IP accounting,
whose BPF maps get recreated on reload/reexec and the previous values
are exclusively retrievable from deserialization. Let's hence swap things
around and serialize cgroup_path first, accounting data only afterwards.

(cherry picked from commit 055a5a236c6776fa281890aa17972c6ed3a1132e)
2025-10-13 16:59:40 +02:00
Mike Yuan
7c85318b34 core/cgroup: realign macro line continuation
(cherry picked from commit e99f741cdf714c900fc6cafc53d19701ed6b02a1)
2025-10-13 16:59:40 +02:00
Yu Watanabe
67f1eeff2a pidfd-util: add missing trailing argument for ioctl(PIDFD_GET_*_NAMESPACE)
Otherwise, it always fails with EINVAL.

(cherry picked from commit 608fc3fa2c4902d84fd925b328b730d3b2dbff50)
2025-10-13 16:59:40 +02:00
n0099
c286c9c894 nspawn: correct the option name --private-users-ownership= when it's not expected value
(cherry picked from commit 613f7f26aa7524b7f2c9a6246e4ecfbecb40c4fa)
2025-10-13 16:59:40 +02:00
Felix Pehla
a228628012 shared/bootspec: parse loader.conf options added in v258
(cherry picked from commit aaa3e6880da71c2faefb619ea7a974dab6a8443d)
2025-10-13 16:59:40 +02:00
Felix Pehla
f7840ac0e0 shared/bootspec: parse 'uki' boot entry option
Commit e2a3d562189c413de3262ec47cdc1e1b0b13d78b (as part of #36314)
makes sd-boot recognize a 'uki' stanza in a boot loader entry and
uapi-group/specifications@3f2bd8236d adds
it to the BLS, but bootctl and other components parsing said config do
not know about it, leading to the error message
`Unknown line 'uki', ignoring.` when attempting to parse the same entry.

This commit makes it get parsed the same way that that 'efi' is.

(cherry picked from commit 4a94a1b83f8857b906bc7924b3f853768b5499b5)
2025-10-13 16:59:40 +02:00
Managor
b734f8d37b systemctl.xml: fix line breaks in documentation anchor links
This combines two commits:
(cherry picked from commit 9f4f7f0372688127adc27f82a75db58749eb6d6e)
+
(cherry picked from commit b0fe317d14c4e9a02ff661c2ccd37f093cfda396)
2025-10-13 16:59:40 +02:00
32 changed files with 276 additions and 85 deletions

View File

@ -825,12 +825,9 @@ mouse:usb:v0e8fp00a7:name:DaKai 2.4G RX:*
# Nulea # Nulea
########################################## ##########################################
# Note: it is possible that other devices may use the same wireless dongle, # Note: The Nulea uses a generic USB dongle. Overriding its value would cause
# as such this could require revisiting if it causes issues with other mice # other mice to be erroneously registered as trackballs, so only bluetooth
# Nulea M501 Wireless Trackball (USB Receiver) # detection is added.
mouse:usb:v25a7pfa61:name:Compx 2.4G Receiver Mouse:*
ID_INPUT_TRACKBALL=1
# Nulea M501 Wireless Trackball (Bluetooth) # Nulea M501 Wireless Trackball (Bluetooth)
mouse:bluetooth:v000ep3412:name:Nulea BT5.0 Mouse:* mouse:bluetooth:v000ep3412:name:Nulea BT5.0 Mouse:*
ID_INPUT_TRACKBALL=1 ID_INPUT_TRACKBALL=1

View File

@ -375,10 +375,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term> <term><command>list-dependencies</command> <optional><replaceable>UNIT</replaceable></optional></term>
<command>list-dependencies</command>
<optional><replaceable>UNIT</replaceable>...</optional>
</term>
<listitem> <listitem>
<para>Shows units required and wanted by the specified <para>Shows units required and wanted by the specified
@ -694,12 +691,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term> <term><command>bind</command> <replaceable>UNIT</replaceable> <replaceable>PATH</replaceable> [<replaceable>PATH</replaceable>]</term>
<command>bind</command>
<replaceable>UNIT</replaceable>
<replaceable>PATH</replaceable>
[<replaceable>PATH</replaceable>]
</term>
<listitem><para>Bind-mounts a file or directory from the host into the specified unit's mount <listitem><para>Bind-mounts a file or directory from the host into the specified unit's mount
namespace. The first path argument is the source file or directory on the host, the second path namespace. The first path argument is the source file or directory on the host, the second path
@ -726,13 +718,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term> <term><command>mount-image</command> <replaceable>UNIT</replaceable> <replaceable>IMAGE</replaceable> [<replaceable>PATH</replaceable> [<replaceable>PARTITION_NAME</replaceable>:<replaceable>MOUNT_OPTIONS</replaceable>]]</term>
<command>mount-image</command>
<replaceable>UNIT</replaceable>
<replaceable>IMAGE</replaceable>
[<replaceable>PATH</replaceable>
[<replaceable>PARTITION_NAME</replaceable>:<replaceable>MOUNT_OPTIONS</replaceable>]]
</term>
<listitem><para>Mounts an image from the host into the specified unit's mount namespace. The first <listitem><para>Mounts an image from the host into the specified unit's mount namespace. The first
path argument is the source image on the host, the second path argument is the destination path argument is the source image on the host, the second path argument is the destination
@ -1215,10 +1201,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><command>add-wants <replaceable>TARGET</replaceable> <term><command>add-wants <replaceable>TARGET</replaceable> <replaceable>UNIT</replaceable></command></term>
<replaceable>UNIT</replaceable></command></term> <term><command>add-requires <replaceable>TARGET</replaceable> <replaceable>UNIT</replaceable></command></term>
<term><command>add-requires <replaceable>TARGET</replaceable>
<replaceable>UNIT</replaceable></command></term>
<listitem> <listitem>
<para>Adds <literal>Wants=</literal> or <literal>Requires=</literal> <para>Adds <literal>Wants=</literal> or <literal>Requires=</literal>
@ -1444,10 +1428,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term> <term><command>import-environment</command> <replaceable>VARIABLE…</replaceable></term>
<command>import-environment</command>
<replaceable>VARIABLE…</replaceable>
</term>
<listitem> <listitem>
<para>Import all, one or more environment variables set on the client into the systemd manager <para>Import all, one or more environment variables set on the client into the systemd manager

View File

@ -488,7 +488,7 @@
<filename>*.pcrlock.d/*.pcrlock</filename> files from. May be used more than once to specify multiple <filename>*.pcrlock.d/*.pcrlock</filename> files from. May be used more than once to specify multiple
such directories. If not specified, defaults to <filename>/etc/pcrlock.d/</filename>, such directories. If not specified, defaults to <filename>/etc/pcrlock.d/</filename>,
<filename>/run/pcrlock.d/</filename>, <filename>/var/lib/pcrlock.d/</filename>, <filename>/run/pcrlock.d/</filename>, <filename>/var/lib/pcrlock.d/</filename>,
<filename>/usr/local/pcrlock.d/</filename>, <filename>/usr/lib/pcrlock.d/</filename>.</para> <filename>/usr/local/lib/pcrlock.d/</filename>, <filename>/usr/lib/pcrlock.d/</filename>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem> <xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry> </varlistentry>

View File

@ -28,8 +28,8 @@
<member><filename>/run/pcrlock.d/*.pcrlock.d/*.pcrlock</filename></member> <member><filename>/run/pcrlock.d/*.pcrlock.d/*.pcrlock</filename></member>
<member><filename>/var/lib/pcrlock.d/*.pcrlock</filename></member> <member><filename>/var/lib/pcrlock.d/*.pcrlock</filename></member>
<member><filename>/var/lib/pcrlock.d/*.pcrlock.d/*.pcrlock</filename></member> <member><filename>/var/lib/pcrlock.d/*.pcrlock.d/*.pcrlock</filename></member>
<member><filename>/usr/local/pcrlock.d/*.pcrlock</filename></member> <member><filename>/usr/local/lib/pcrlock.d/*.pcrlock</filename></member>
<member><filename>/usr/local/pcrlock.d/*.pcrlock.d/*.pcrlock</filename></member> <member><filename>/usr/local/lib/pcrlock.d/*.pcrlock.d/*.pcrlock</filename></member>
<member><filename>/usr/lib/pcrlock.d/*.pcrlock</filename></member> <member><filename>/usr/lib/pcrlock.d/*.pcrlock</filename></member>
<member><filename>/usr/lib/pcrlock.d/*.pcrlock.d/*.pcrlock</filename></member> <member><filename>/usr/lib/pcrlock.d/*.pcrlock.d/*.pcrlock</filename></member>
</simplelist></para> </simplelist></para>

View File

@ -1 +1 @@
258 258.1

View File

@ -56,7 +56,7 @@ int pidfd_get_namespace(int fd, unsigned long ns_type_cmd) {
if (have_pidfs == 0 || !cached_supported) if (have_pidfs == 0 || !cached_supported)
return -EOPNOTSUPP; return -EOPNOTSUPP;
int nsfd = ioctl(fd, ns_type_cmd); int nsfd = ioctl(fd, ns_type_cmd, 0);
if (nsfd < 0) { if (nsfd < 0) {
/* Kernel returns EOPNOTSUPP if the ns type in question is disabled. Hence we need to look /* Kernel returns EOPNOTSUPP if the ns type in question is disabled. Hence we need to look
* at precise errno instead of generic ERRNO_IS_(IOCTL_)NOT_SUPPORTED. */ * at precise errno instead of generic ERRNO_IS_(IOCTL_)NOT_SUPPORTED. */

View File

@ -732,6 +732,9 @@ static int count_known_files(const BootConfig *config, const char* root, Hashmap
if (r < 0) if (r < 0)
return r; return r;
r = ref_file(&known_files, e->efi, +1); r = ref_file(&known_files, e->efi, +1);
if (r < 0)
return r;
r = ref_file(&known_files, e->uki, +1);
if (r < 0) if (r < 0)
return r; return r;
STRV_FOREACH(s, e->initrd) { STRV_FOREACH(s, e->initrd) {
@ -792,6 +795,7 @@ static int unlink_entry(const BootConfig *config, const char *root, const char *
deref_unlink_file(&known_files, e->kernel, e->root); deref_unlink_file(&known_files, e->kernel, e->root);
deref_unlink_file(&known_files, e->efi, e->root); deref_unlink_file(&known_files, e->efi, e->root);
deref_unlink_file(&known_files, e->uki, e->root);
STRV_FOREACH(s, e->initrd) STRV_FOREACH(s, e->initrd)
deref_unlink_file(&known_files, *s, e->root); deref_unlink_file(&known_files, *s, e->root);
deref_unlink_file(&known_files, e->device_tree, e->root); deref_unlink_file(&known_files, e->device_tree, e->root);

View File

@ -547,9 +547,9 @@ int bpf_firewall_compile(Unit *u) {
if (!cc) if (!cc)
return -EINVAL; return -EINVAL;
crt = unit_setup_cgroup_runtime(u); crt = unit_get_cgroup_runtime(u);
if (!crt) if (!crt)
return -ENOMEM; return -ESTALE;
if (bpf_program_supported() <= 0) if (bpf_program_supported() <= 0)
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),

View File

@ -4262,6 +4262,15 @@ int cgroup_runtime_serialize(Unit *u, FILE *f, FDSet *fds) {
if (!crt) if (!crt)
return 0; return 0;
if (crt->cgroup_path)
(void) serialize_item(f, "cgroup", crt->cgroup_path);
if (crt->cgroup_id != 0)
(void) serialize_item_format(f, "cgroup-id", "%" PRIu64, crt->cgroup_id);
(void) serialize_cgroup_mask(f, "cgroup-realized-mask", crt->cgroup_realized_mask);
(void) serialize_cgroup_mask(f, "cgroup-enabled-mask", crt->cgroup_enabled_mask);
(void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", crt->cgroup_invalidated_mask);
(void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, crt->cpu_usage_base); (void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, crt->cpu_usage_base);
if (crt->cpu_usage_last != NSEC_INFINITY) if (crt->cpu_usage_last != NSEC_INFINITY)
(void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, crt->cpu_usage_last); (void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, crt->cpu_usage_last);
@ -4295,15 +4304,6 @@ int cgroup_runtime_serialize(Unit *u, FILE *f, FDSet *fds) {
(void) serialize_item_format(f, io_accounting_metric_field_last_to_string(im), "%" PRIu64, crt->io_accounting_last[im]); (void) serialize_item_format(f, io_accounting_metric_field_last_to_string(im), "%" PRIu64, crt->io_accounting_last[im]);
} }
if (crt->cgroup_path)
(void) serialize_item(f, "cgroup", crt->cgroup_path);
if (crt->cgroup_id != 0)
(void) serialize_item_format(f, "cgroup-id", "%" PRIu64, crt->cgroup_id);
(void) serialize_cgroup_mask(f, "cgroup-realized-mask", crt->cgroup_realized_mask);
(void) serialize_cgroup_mask(f, "cgroup-enabled-mask", crt->cgroup_enabled_mask);
(void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", crt->cgroup_invalidated_mask);
(void) bpf_socket_bind_serialize(u, f, fds); (void) bpf_socket_bind_serialize(u, f, fds);
(void) bpf_program_serialize_attachment(f, fds, "ip-bpf-ingress-installed", crt->ip_bpf_ingress_installed); (void) bpf_program_serialize_attachment(f, fds, "ip-bpf-ingress-installed", crt->ip_bpf_ingress_installed);
@ -4330,7 +4330,7 @@ int cgroup_runtime_serialize(Unit *u, FILE *f, FDSet *fds) {
log_unit_debug_errno(u, _deserialize_r, \ log_unit_debug_errno(u, _deserialize_r, \
"Failed to parse \"%s=%s\", ignoring.", l, v); \ "Failed to parse \"%s=%s\", ignoring.", l, v); \
else \ else \
crt->target = _deserialize_r; \ crt->target = _deserialize_r; \
} \ } \
} \ } \
_deserialize_matched; \ _deserialize_matched; \
@ -4353,7 +4353,7 @@ int cgroup_runtime_serialize(Unit *u, FILE *f, FDSet *fds) {
_deserialize_matched; \ _deserialize_matched; \
}) })
#define MATCH_DESERIALIZE_METRIC(u, key, l, v, parse_func, target) \ #define MATCH_DESERIALIZE_METRIC(u, key, l, v, parse_func, target) \
({ \ ({ \
bool _deserialize_matched = streq(l, key); \ bool _deserialize_matched = streq(l, key); \
if (_deserialize_matched) { \ if (_deserialize_matched) { \
@ -4366,7 +4366,7 @@ int cgroup_runtime_serialize(Unit *u, FILE *f, FDSet *fds) {
log_unit_debug_errno(u, _deserialize_r, \ log_unit_debug_errno(u, _deserialize_r, \
"Failed to parse \"%s=%s\", ignoring.", l, v); \ "Failed to parse \"%s=%s\", ignoring.", l, v); \
else \ else \
crt->target = _deserialize_r; \ crt->target = _deserialize_r; \
} \ } \
} \ } \
_deserialize_matched; \ _deserialize_matched; \

View File

@ -772,8 +772,8 @@ static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult
/* No message on the console if the job did not actually do anything due to unmet condition. */ /* No message on the console if the job did not actually do anything due to unmet condition. */
if (console_only) if (console_only)
return; return;
else
do_console = false; do_console = false;
} }
if (!console_only) { /* Skip printing if output goes to the console, and job_print_status_message() if (!console_only) { /* Skip printing if output goes to the console, and job_print_status_message()

View File

@ -136,7 +136,7 @@ static usec_t manager_watch_jobs_next_time(Manager *m) {
/* Let the user manager without a timeout show status quickly, so the system manager can make /* Let the user manager without a timeout show status quickly, so the system manager can make
* use of it, if it wants to. */ * use of it, if it wants to. */
timeout = JOBS_IN_PROGRESS_WAIT_USEC * 2 / 3; timeout = JOBS_IN_PROGRESS_WAIT_USEC * 2 / 3;
else if (show_status_on(m->show_status)) else if (manager_get_show_status_on(m))
/* When status is on, just use the usual timeout. */ /* When status is on, just use the usual timeout. */
timeout = JOBS_IN_PROGRESS_WAIT_USEC; timeout = JOBS_IN_PROGRESS_WAIT_USEC;
else else
@ -4522,10 +4522,10 @@ static bool manager_should_show_status(Manager *m, StatusType type) {
return false; return false;
/* If we cannot find out the status properly, just proceed. */ /* If we cannot find out the status properly, just proceed. */
if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0) if (type < STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
return false; return false;
if (type == STATUS_TYPE_NOTICE && m->show_status != SHOW_STATUS_NO) if (type >= STATUS_TYPE_NOTICE && manager_get_show_status(m) != SHOW_STATUS_NO)
return true; return true;
return manager_get_show_status_on(m); return manager_get_show_status_on(m);

View File

@ -664,8 +664,6 @@ static int timer_start(Unit *u) {
if (r < 0) if (r < 0)
return r; return r;
t->last_trigger = DUAL_TIMESTAMP_NULL;
/* Reenable all timers that depend on unit activation time */ /* Reenable all timers that depend on unit activation time */
LIST_FOREACH(value, v, t->values) LIST_FOREACH(value, v, t->values)
if (v->base == TIMER_ACTIVE) if (v->base == TIMER_ACTIVE)

View File

@ -1825,7 +1825,15 @@ static bool unit_test_assert(Unit *u) {
return u->assert_result; return u->assert_result;
} }
void unit_status_printf(Unit *u, StatusType status_type, const char *status, const char *format, const char *ident) { void unit_status_printf(
Unit *u,
StatusType status_type,
const char *status,
const char *format,
const char *ident) {
assert(u);
if (log_get_show_color()) { if (log_get_show_color()) {
if (u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED && strchr(ident, ' ')) if (u->manager->status_unit_format == STATUS_UNIT_FORMAT_COMBINED && strchr(ident, ' '))
ident = strjoina(ANSI_HIGHLIGHT, u->id, ANSI_NORMAL, " - ", u->description); ident = strjoina(ANSI_HIGHLIGHT, u->id, ANSI_NORMAL, " - ", u->description);

View File

@ -52,10 +52,12 @@ typedef enum OOMPolicy {
} OOMPolicy; } OOMPolicy;
typedef enum StatusType { typedef enum StatusType {
STATUS_TYPE_EPHEMERAL, STATUS_TYPE_EPHEMERAL, /* ordered by severity! Do not break order */
STATUS_TYPE_NORMAL, STATUS_TYPE_NORMAL,
STATUS_TYPE_NOTICE, STATUS_TYPE_NOTICE,
STATUS_TYPE_EMERGENCY, STATUS_TYPE_EMERGENCY,
_STATUS_TYPE_MAX,
_STATUS_TYPE_INVALID = -EINVAL,
} StatusType; } StatusType;
static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) { static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) {

View File

@ -404,9 +404,11 @@ int machine_load(Machine *m) {
log_warning_errno(r, "Failed to parse AF_VSOCK CID, ignoring: %s", vsock_cid); log_warning_errno(r, "Failed to parse AF_VSOCK CID, ignoring: %s", vsock_cid);
} }
r = parse_uid(uid, &m->uid); if (uid) {
if (r < 0) r = parse_uid(uid, &m->uid);
log_warning_errno(r, "Failed to parse owning UID, ignoring: %s", uid); if (r < 0)
log_warning_errno(r, "Failed to parse owning UID, ignoring: %s", uid);
}
return r; return r;
} }

View File

@ -1247,7 +1247,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_userns_ownership = user_namespace_ownership_from_string(optarg); arg_userns_ownership = user_namespace_ownership_from_string(optarg);
if (arg_userns_ownership < 0) if (arg_userns_ownership < 0)
return log_error_errno(arg_userns_ownership, "Cannot parse --user-namespace-ownership= value: %s", optarg); return log_error_errno(arg_userns_ownership, "Cannot parse --private-users-ownership= value: %s", optarg);
arg_settings_mask |= SETTING_USERNS; arg_settings_mask |= SETTING_USERNS;
break; break;

View File

@ -93,6 +93,7 @@ static void boot_entry_free(BootEntry *entry) {
boot_entry_addons_done(&entry->local_addons); boot_entry_addons_done(&entry->local_addons);
free(entry->kernel); free(entry->kernel);
free(entry->efi); free(entry->efi);
free(entry->uki);
strv_free(entry->initrd); strv_free(entry->initrd);
free(entry->device_tree); free(entry->device_tree);
strv_free(entry->device_tree_overlay); strv_free(entry->device_tree_overlay);
@ -403,6 +404,8 @@ static int boot_entry_load_type1(
r = parse_path_one(tmp.path, line, field, &tmp.kernel, p); r = parse_path_one(tmp.path, line, field, &tmp.kernel, p);
else if (streq(field, "efi")) else if (streq(field, "efi"))
r = parse_path_one(tmp.path, line, field, &tmp.efi, p); r = parse_path_one(tmp.path, line, field, &tmp.efi, p);
else if (streq(field, "uki"))
r = parse_path_one(tmp.path, line, field, &tmp.uki, p);
else if (streq(field, "initrd")) else if (streq(field, "initrd"))
r = parse_path_strv(tmp.path, line, field, &tmp.initrd, p); r = parse_path_strv(tmp.path, line, field, &tmp.initrd, p);
else if (streq(field, "devicetree")) else if (streq(field, "devicetree"))
@ -511,7 +514,8 @@ int boot_loader_read_conf(BootConfig *config, FILE *file, const char *path) {
r = free_and_strdup(&config->default_pattern, p); r = free_and_strdup(&config->default_pattern, p);
else if (STR_IN_SET(field, "timeout", "editor", "auto-entries", "auto-firmware", else if (STR_IN_SET(field, "timeout", "editor", "auto-entries", "auto-firmware",
"auto-poweroff", "auto-reboot", "beep", "reboot-for-bitlocker", "auto-poweroff", "auto-reboot", "beep", "reboot-for-bitlocker",
"secure-boot-enroll", "console-mode")) "reboot-on-error", "secure-boot-enroll", "secure-boot-enroll-action",
"console-mode"))
r = 0; /* we don't parse these in userspace, but they are OK */ r = 0; /* we don't parse these in userspace, but they are OK */
else { else {
log_syntax(NULL, LOG_WARNING, path, line, 0, "Unknown line '%s', ignoring.", field); log_syntax(NULL, LOG_WARNING, path, line, 0, "Unknown line '%s', ignoring.", field);
@ -1896,6 +1900,8 @@ int show_boot_entry(
boot_entry_file_list("linux", e->root, e->kernel, &status); boot_entry_file_list("linux", e->root, e->kernel, &status);
if (e->efi) if (e->efi)
boot_entry_file_list("efi", e->root, e->efi, &status); boot_entry_file_list("efi", e->root, e->efi, &status);
if (e->uki)
boot_entry_file_list("uki", e->root, e->uki, &status);
STRV_FOREACH(s, e->initrd) STRV_FOREACH(s, e->initrd)
boot_entry_file_list(s == e->initrd ? "initrd" : NULL, boot_entry_file_list(s == e->initrd ? "initrd" : NULL,
@ -1957,9 +1963,8 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
SD_JSON_BUILD_PAIR_CONDITION(!!opts, "options", SD_JSON_BUILD_STRING(opts)), SD_JSON_BUILD_PAIR_CONDITION(!!opts, "options", SD_JSON_BUILD_STRING(opts)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->kernel, "linux", SD_JSON_BUILD_STRING(e->kernel)), SD_JSON_BUILD_PAIR_CONDITION(!!e->kernel, "linux", SD_JSON_BUILD_STRING(e->kernel)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->efi, "efi", SD_JSON_BUILD_STRING(e->efi)), SD_JSON_BUILD_PAIR_CONDITION(!!e->efi, "efi", SD_JSON_BUILD_STRING(e->efi)),
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(e->initrd), "initrd", SD_JSON_BUILD_STRV(e->initrd)), SD_JSON_BUILD_PAIR_CONDITION(!!e->uki, "uki", SD_JSON_BUILD_STRING(e->uki)),
SD_JSON_BUILD_PAIR_CONDITION(!!e->device_tree, "devicetree", SD_JSON_BUILD_STRING(e->device_tree)), SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(e->initrd), "initrd", SD_JSON_BUILD_STRV(e->initrd)));
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(e->device_tree_overlay), "devicetreeOverlay", SD_JSON_BUILD_STRV(e->device_tree_overlay)));
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
@ -1968,6 +1973,8 @@ int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret) {
* at once. */ * at once. */
r = sd_json_variant_merge_objectbo( r = sd_json_variant_merge_objectbo(
&v, &v,
SD_JSON_BUILD_PAIR_CONDITION(!!e->device_tree, "devicetree", SD_JSON_BUILD_STRING(e->device_tree)),
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(e->device_tree_overlay), "devicetreeOverlay", SD_JSON_BUILD_STRV(e->device_tree_overlay)),
SD_JSON_BUILD_PAIR("isReported", SD_JSON_BUILD_BOOLEAN(e->reported_by_loader)), SD_JSON_BUILD_PAIR("isReported", SD_JSON_BUILD_BOOLEAN(e->reported_by_loader)),
SD_JSON_BUILD_PAIR_CONDITION(e->tries_left != UINT_MAX, "triesLeft", SD_JSON_BUILD_UNSIGNED(e->tries_left)), SD_JSON_BUILD_PAIR_CONDITION(e->tries_left != UINT_MAX, "triesLeft", SD_JSON_BUILD_UNSIGNED(e->tries_left)),
SD_JSON_BUILD_PAIR_CONDITION(e->tries_done != UINT_MAX, "triesDone", SD_JSON_BUILD_UNSIGNED(e->tries_done)), SD_JSON_BUILD_PAIR_CONDITION(e->tries_done != UINT_MAX, "triesDone", SD_JSON_BUILD_UNSIGNED(e->tries_done)),

View File

@ -50,6 +50,7 @@ typedef struct BootEntry {
const BootEntryAddons *global_addons; /* Backpointer into the BootConfig; we don't own this here */ const BootEntryAddons *global_addons; /* Backpointer into the BootConfig; we don't own this here */
char *kernel; /* linux is #defined to 1, yikes! */ char *kernel; /* linux is #defined to 1, yikes! */
char *efi; char *efi;
char *uki;
char **initrd; char **initrd;
char *device_tree; char *device_tree;
char **device_tree_overlay; char **device_tree_overlay;

View File

@ -47,6 +47,7 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(options, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(options, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(linux, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(linux, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(efi, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(efi, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(uki, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(initrd, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY), SD_VARLINK_DEFINE_FIELD(initrd, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),
SD_VARLINK_DEFINE_FIELD(devicetree, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(devicetree, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(devicetreeOverlay, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY), SD_VARLINK_DEFINE_FIELD(devicetreeOverlay, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY),

View File

@ -1830,10 +1830,7 @@ static int merge_subprocess(
if (r < 0) if (r < 0)
return r; return r;
r = dissected_image_decrypt_interactively( r = dissected_image_decrypt(m, /* passphrase= */ NULL, &verity_settings, flags);
m, NULL,
&verity_settings,
flags);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -132,7 +132,7 @@ _sd_const_ static __inline__ int sd_id128_is_allf(sd_id128_t a) {
#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }}) #define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }})
#define SD_ID128_ALLF ((const sd_id128_t) { .qwords = { UINT64_C(0xFFFFFFFFFFFFFFFF), UINT64_C(0xFFFFFFFFFFFFFFFF) }}) #define SD_ID128_ALLF ((const sd_id128_t) { .qwords = { UINT64_C(0xFFFFFFFFFFFFFFFF), UINT64_C(0xFFFFFFFFFFFFFFFF) }})
_sd_const_ static __inline__ int sd_id128_in_setv(sd_id128_t a, va_list ap) { static __inline__ int sd_id128_in_setv(sd_id128_t a, va_list ap) {
for (;;) { for (;;) {
sd_id128_t b = va_arg(ap, sd_id128_t); sd_id128_t b = va_arg(ap, sd_id128_t);

View File

@ -50,7 +50,8 @@ int main(int argc, char *argv[]) {
if (!can_memlock()) if (!can_memlock())
return log_tests_skipped("Can't use mlock()"); return log_tests_skipped("Can't use mlock()");
r = enter_cgroup_subroot(NULL); _cleanup_free_ char *cgroup_path = NULL;
r = enter_cgroup_subroot(&cgroup_path);
if (r == -ENOMEDIUM) if (r == -ENOMEDIUM)
return log_tests_skipped("cgroupfs not available"); return log_tests_skipped("cgroupfs not available");
@ -129,6 +130,8 @@ int main(int argc, char *argv[]) {
SERVICE(u)->type = SERVICE_ONESHOT; SERVICE(u)->type = SERVICE_ONESHOT;
u->load_state = UNIT_LOADED; u->load_state = UNIT_LOADED;
CGroupRuntime *crt = ASSERT_PTR(unit_setup_cgroup_runtime(u));
unit_dump(u, stdout, NULL); unit_dump(u, stdout, NULL);
r = bpf_firewall_compile(u); r = bpf_firewall_compile(u);
@ -136,7 +139,6 @@ int main(int argc, char *argv[]) {
return log_tests_skipped("Kernel doesn't support the necessary bpf bits (masked out via seccomp?)"); return log_tests_skipped("Kernel doesn't support the necessary bpf bits (masked out via seccomp?)");
ASSERT_OK(r); ASSERT_OK(r);
CGroupRuntime *crt = ASSERT_PTR(unit_get_cgroup_runtime(u));
ASSERT_NOT_NULL(crt->ip_bpf_ingress); ASSERT_NOT_NULL(crt->ip_bpf_ingress);
ASSERT_NOT_NULL(crt->ip_bpf_egress); ASSERT_NOT_NULL(crt->ip_bpf_egress);

View File

@ -151,6 +151,7 @@ udev_binaries_dict = [
include_directories('.', 'net'), include_directories('.', 'net'),
], ],
'dependencies' : udev_dependencies, 'dependencies' : udev_dependencies,
'link_with' : udev_link_with,
'install_rpath' : udev_rpath, 'install_rpath' : udev_rpath,
'install_tag' : 'udev', 'install_tag' : 'udev',
'extract' : udevadm_extract_sources, 'extract' : udevadm_extract_sources,

View File

@ -70,7 +70,7 @@ foreach dirname : [
'TEST-46-HOMED', 'TEST-46-HOMED',
'TEST-50-DISSECT', 'TEST-50-DISSECT',
'TEST-52-HONORFIRSTSHUTDOWN', 'TEST-52-HONORFIRSTSHUTDOWN',
'TEST-53-ISSUE-16347', 'TEST-53-TIMER',
'TEST-54-CREDS', 'TEST-54-CREDS',
'TEST-55-OOMD', 'TEST-55-OOMD',
'TEST-58-REPART', 'TEST-58-REPART',

View File

@ -0,0 +1,97 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# When deserializing a serialized timer unit with RandomizedDelaySec= set, systemd should use the last
# inactive exit timestamp instead of current realtime to calculate the new next elapse, so the timer unit
# actually runs in the given calendar window.
#
# Provides coverage for:
# - https://github.com/systemd/systemd/issues/18678
# - https://github.com/systemd/systemd/pull/27752
set -eux
set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/util.sh
UNIT_NAME="timer-RandomizedDelaySec-$RANDOM"
TARGET_TS="$(date --date="tomorrow 00:10")"
TARGET_TS_S="$(date --date="$TARGET_TS" "+%s")"
# Maximum possible next elapse timestamp: $TARGET_TS (OnCalendar=) + 22 hours (RandomizedDelaySec=)
MAX_NEXT_ELAPSE_REALTIME_S="$((TARGET_TS_S + 22 * 60 * 60))"
MAX_NEXT_ELAPSE_REALTIME="$(date --date="@$MAX_NEXT_ELAPSE_REALTIME_S")"
# Let's make sure to return the date & time back to the original state once we're done with our time
# shenigans. One way to do this would be to use hwclock, but the RTC in VMs can be unreliable or slow to
# respond, causing unexpected test fails/timeouts.
#
# Instead, let's save the realtime timestamp before we start with the test together with a current monotonic
# timestamp, after the test ends take the difference between the current monotonic timestamp and the "start"
# one, add it to the originally saved realtime timestamp, and finally use that timestamp to set the system
# time. This should advance the system time by the amount of time the test actually ran, and hence restore it
# to some sane state after the time jumps performed by the test. It won't be perfect, but it should be close
# enough for our needs.
START_REALTIME="$(date "+%s")"
START_MONOTONIC="$(cut -d . -f 1 /proc/uptime)"
at_exit() {
: "Restore the system date to a sane state"
END_MONOTONIC="$(cut -d . -f 1 /proc/uptime)"
date --set="@$((START_REALTIME + END_MONOTONIC - START_MONOTONIC))"
}
trap at_exit EXIT
# Set some predictable time so we can schedule the first timer elapse in a deterministic-ish way
date --set="23:00"
# Setup
cat >"/run/systemd/system/$UNIT_NAME.timer" <<EOF
[Timer]
# Run this timer daily, ten minutes after midnight
OnCalendar=*-*-* 00:10:00
RandomizedDelaySec=22h
AccuracySec=1ms
EOF
cat >"/run/systemd/system/$UNIT_NAME.service" <<EOF
[Service]
ExecStart=echo "Hello world"
EOF
systemctl daemon-reload
check_elapse_timestamp() {
systemctl status "$UNIT_NAME.timer"
systemctl show -p InactiveExitTimestamp "$UNIT_NAME.timer"
NEXT_ELAPSE_REALTIME="$(systemctl show -P NextElapseUSecRealtime "$UNIT_NAME.timer")"
NEXT_ELAPSE_REALTIME_S="$(date --date="$NEXT_ELAPSE_REALTIME" "+%s")"
: "Next elapse timestamp should be $TARGET_TS <= $NEXT_ELAPSE_REALTIME <= $MAX_NEXT_ELAPSE_REALTIME"
assert_ge "$NEXT_ELAPSE_REALTIME_S" "$TARGET_TS_S"
assert_le "$NEXT_ELAPSE_REALTIME_S" "$MAX_NEXT_ELAPSE_REALTIME_S"
}
# Restart the timer unit and check the initial next elapse timestamp
: "Initial next elapse timestamp"
systemctl restart "$UNIT_NAME.timer"
check_elapse_timestamp
# Bump the system date to 1 minute after the original calendar timer would've expired (without any random
# delay!) - systemd should recalculate the next elapse timestamp with a new randomized delay, but it should
# use the original inactive exit timestamp as a "base", so the final timestamp should not end up beyond the
# original calendar timestamp + randomized delay range.
#
# Similarly, do the same check after doing daemon-reload, as that also forces systemd to recalculate the next
# elapse timestamp (this goes through a slightly different codepath that actually contained the original
# issue).
: "Next elapse timestamp after time jump"
date -s "tomorrow 00:11"
check_elapse_timestamp
: "Next elapse timestamp after daemon-reload"
systemctl daemon-reload
check_elapse_timestamp
# Cleanup
systemctl stop "$UNIT_NAME".{timer,service}
rm -f "/run/systemd/system/$UNIT_NAME".{timer,service}
systemctl daemon-reload

View File

@ -3,10 +3,9 @@
set -eux set -eux
set -o pipefail set -o pipefail
: >/failed
# Reset host date to current time, 3 days in the past. # Reset host date to current time, 3 days in the past.
date -s "-3 days" date -s "-3 days"
trap 'date -s "+3 days"' EXIT
# Run a timer for every 15 minutes. # Run a timer for every 15 minutes.
systemd-run --unit test-timer --on-calendar "*:0/15:0" true systemd-run --unit test-timer --on-calendar "*:0/15:0" true
@ -17,15 +16,12 @@ now=$(date +%s)
time_delta=$((next_elapsed - now)) time_delta=$((next_elapsed - now))
# Check that the timer will elapse in less than 20 minutes. # Check that the timer will elapse in less than 20 minutes.
((0 < time_delta && time_delta < 1200)) || { if [[ "$time_delta" -lt 0 || "$time_delta" -gt 1200 ]]; then
echo 'Timer elapse outside of the expected 20 minute window.' echo 'Timer elapse outside of the expected 20 minute window.'
echo " next_elapsed=${next_elapsed}" echo " next_elapsed=${next_elapsed}"
echo " now=${now}" echo " now=${now}"
echo " time_delta=${time_delta}" echo " time_delta=${time_delta}"
echo '' echo
} >>/failed
if test ! -s /failed ; then exit 1
rm -f /failed
touch /testok
fi fi

View File

@ -0,0 +1,77 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# Restarting an already elapsed timer shouldn't immediately trigger the corresponding service unit.
#
# Provides coverage for:
# - https://github.com/systemd/systemd/issues/31231
# - https://github.com/systemd/systemd/issues/35805
set -eux
set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/util.sh
UNIT_NAME="timer-restart-$RANDOM"
TEST_MESSAGE="Hello from timer $RANDOM"
# Setup
cat >"/run/systemd/system/$UNIT_NAME.timer" <<EOF
[Timer]
OnCalendar=$(date --date="+1 hour" "+%Y-%m-%d %H:%M:%S")
AccuracySec=1s
EOF
cat >"/run/systemd/system/$UNIT_NAME.service" <<EOF
[Service]
ExecStart=echo "$TEST_MESSAGE"
EOF
systemctl daemon-reload
JOURNAL_TS="$(date "+%s")"
# Paranoia check that the test message is not already in the logs
(! journalctl -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE")
# Restart time timer and move time forward by 2 hours to trigger the timer
systemctl restart "$UNIT_NAME.timer"
systemctl status "$UNIT_NAME.timer"
date -s '+2 hours'
trap 'date -s "-2 hours"' EXIT
sleep 1
systemctl status "$UNIT_NAME.timer"
assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE" | wc -l)" "1"
# Restarting the timer unit shouldn't trigger neither the timer nor the service, so these
# fields should remain constant through the following tests
SERVICE_INV_ID="$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
TIMER_LAST_TRIGGER="$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
# Now restart the timer and check if the timer and the service weren't triggered again
systemctl restart "$UNIT_NAME.timer"
sleep 5
assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE" | wc -l)" "1"
assert_eq "$SERVICE_INV_ID" "$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
assert_eq "$TIMER_LAST_TRIGGER" "$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
# Set the timer into the past, restart it, and again check if it wasn't triggered
TIMER_TS="$(date --date="-1 day" "+%Y-%m-%d %H:%M:%S")"
mkdir "/run/systemd/system/$UNIT_NAME.timer.d/"
cat >"/run/systemd/system/$UNIT_NAME.timer.d/99-override.conf" <<EOF
[Timer]
OnCalendar=$TIMER_TS
EOF
systemctl daemon-reload
systemctl status "$UNIT_NAME.timer"
assert_in "OnCalendar=$TIMER_TS" "$(systemctl show -P TimersCalendar "$UNIT_NAME".timer)"
systemctl restart "$UNIT_NAME.timer"
sleep 5
assert_eq "$(journalctl -q -p info --since="@$JOURNAL_TS" --unit="$UNIT_NAME" --grep="$TEST_MESSAGE" | wc -l)" "1"
assert_eq "$SERVICE_INV_ID" "$(systemctl show --property=InvocationID "$UNIT_NAME.service")"
assert_eq "$TIMER_LAST_TRIGGER" "$(systemctl show --property=LastTriggerUSec "$UNIT_NAME.timer")"
# Cleanup
systemctl stop "$UNIT_NAME".{timer,service}
rm -f "/run/systemd/system/$UNIT_NAME".{timer,service}
systemctl daemon-reload

11
test/units/TEST-53-TIMER.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok

View File

@ -57,6 +57,15 @@ assert_le() {(
fi fi
)} )}
assert_ge() {(
set +ex
if [[ "${1:?}" -lt "${2:?}" ]]; then
echo "FAIL: '$1' < '$2'" >&2
exit 1
fi
)}
assert_in() {( assert_in() {(
set +ex set +ex

View File

@ -18,7 +18,7 @@ Before=sysinit.target shutdown.target
DefaultDependencies=no DefaultDependencies=no
[Service] [Service]
#CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_SYS_RESOURCE CAP_BPF CAP_PERFMON CAP_SETGID CAP_SETUID CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_SYS_RESOURCE CAP_BPF CAP_PERFMON CAP_SETGID CAP_SETUID CAP_DAC_OVERRIDE CAP_CHOWN CAP_SYS_ADMIN
ExecStart={{LIBEXECDIR}}/systemd-mountfsd ExecStart={{LIBEXECDIR}}/systemd-mountfsd
IPAddressDeny=any IPAddressDeny=any
LimitNOFILE={{HIGH_RLIMIT_NOFILE}} LimitNOFILE={{HIGH_RLIMIT_NOFILE}}