From b677e762d518522f868da3fbb4b539e11df80851 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 06 2021 16:12:13 +0000 Subject: import systemd-239-50.el8 --- diff --git a/SOURCES/0544-Revert-test-add-test-cases-for-empty-string-match-an.patch b/SOURCES/0544-Revert-test-add-test-cases-for-empty-string-match-an.patch new file mode 100644 index 0000000..fcfec2d --- /dev/null +++ b/SOURCES/0544-Revert-test-add-test-cases-for-empty-string-match-an.patch @@ -0,0 +1,123 @@ +From b05c8d2e10c773b9bcae17055be48a2291ca6fa6 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 2 Mar 2021 12:57:59 -0500 +Subject: [PATCH] Revert "test: add test cases for empty string match" and + "test: add test case for multi matches when use ||" + +This effectively reverts commits 03bc565e6e3249385c4e1ca0ae27670ca2ad9a41 +and 03b766cc937ffa4dcb7cfb25b2ac20d8a00cb6db. + +Resolves: #1931947 +--- + test/udev-test.pl | 98 ----------------------------------------------- + 1 file changed, 98 deletions(-) + +diff --git a/test/udev-test.pl b/test/udev-test.pl +index 5b1e33504e..0612859cda 100755 +--- a/test/udev-test.pl ++++ b/test/udev-test.pl +@@ -1732,104 +1732,6 @@ KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1" + KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2" + KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right" + KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3" +-EOF +- }, +- { +- desc => "test multi matches 5", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 6", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 7", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 8", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 9", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 10", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < "test multi matches 11", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", +- exp_links => ["found"], +- not_exp_name => "bad", +- }], +- rules => < +Date: Tue, 24 Apr 2018 21:40:23 +0200 +Subject: [PATCH] test/sys-script.py: add missing DEVNAME entries to uevents + +Resolves: #1931947 +--- + test/sys-script.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/test/sys-script.py b/test/sys-script.py +index a51112603e..f4a847e356 100755 +--- a/test/sys-script.py ++++ b/test/sys-script.py +@@ -11677,6 +11677,7 @@ f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0: + f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/uevent', 0o644, b'''MAJOR=8 + MINOR=16 + DEVTYPE=disk ++DEVNAME=sdb + ''') + d('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/queue', 0o755) + l('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/queue/bsg', '../../../bsg/7:0:0:0') +@@ -11709,6 +11710,7 @@ f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0: + f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/sdb1/uevent', 0o644, b'''MAJOR=8 + MINOR=17 + DEVTYPE=partition ++DEVNAME=sdb1 + ''') + d('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/sdb1/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1d.7/usb5/5-1/5-1:1.0/host7/target7:0:0/7:0:0:0/block/sdb/sdb1/power/wakeup', 0o644, b'\n') +@@ -13150,6 +13152,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10 + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10/uevent', 0o644, b'''MAJOR=8 + MINOR=10 + DEVTYPE=partition ++DEVNAME=sda10 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10/power/wakeup', 0o644, b'\n') +@@ -13163,6 +13166,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9/ + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9/uevent', 0o644, b'''MAJOR=8 + MINOR=9 + DEVTYPE=partition ++DEVNAME=sda9 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9/holders', 0o755) + l('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9/holders/md0', '../../../../../../../../../virtual/block/md0') +@@ -13178,6 +13182,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7/ + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7/uevent', 0o644, b'''MAJOR=8 + MINOR=7 + DEVTYPE=partition ++DEVNAME=sda7 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7/power/wakeup', 0o644, b'\n') +@@ -13205,6 +13210,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8/ + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8/uevent', 0o644, b'''MAJOR=8 + MINOR=8 + DEVTYPE=partition ++DEVNAME=sda8 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8/power/wakeup', 0o644, b'\n') +@@ -13232,6 +13238,7 @@ f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6/ + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6/uevent', 0o644, b'''MAJOR=8 + MINOR=6 + DEVTYPE=partition ++DEVNAME=sda6 + ''') + d('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6/power', 0o755) + f('sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6/power/wakeup', 0o644, b'\n') diff --git a/SOURCES/0546-sd-event-split-out-helper-functions-for-reshuffling-.patch b/SOURCES/0546-sd-event-split-out-helper-functions-for-reshuffling-.patch new file mode 100644 index 0000000..afc2d7e --- /dev/null +++ b/SOURCES/0546-sd-event-split-out-helper-functions-for-reshuffling-.patch @@ -0,0 +1,207 @@ +From 4ce10f8e41a85a56ad9b805442eb1149ece7c82a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Fri, 23 Oct 2020 18:29:27 +0200 +Subject: [PATCH] sd-event: split out helper functions for reshuffling prioqs + +We typically don't just reshuffle a single prioq at once, but always +two. Let's add two helper functions that do this, and reuse them +everywhere. + +(Note that this drops one minor optimization: +sd_event_source_set_time_accuracy() previously only reshuffled the +"latest" prioq, since changing the accuracy has no effect on the +earliest time of an event source, just the latest time an event source +can run. This optimization is removed to simplify things, given that +it's not really worth the effort as prioq_reshuffle() on properly +ordered prioqs has practically zero cost O(1)). + +(Slightly generalized, commented and split out of #17284 by Lennart) + +(cherry picked from commit e1951c16a8fbe5b0b9ecc08f4f835a806059d28f) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 96 ++++++++++++------------------ + 1 file changed, 38 insertions(+), 58 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 0d3bf5cbb6..47f99eb096 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -889,6 +889,33 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) + event_unmask_signal_data(e, d, sig); + } + ++static void event_source_pp_prioq_reshuffle(sd_event_source *s) { ++ assert(s); ++ ++ /* Reshuffles the pending + prepare prioqs. Called whenever the dispatch order changes, i.e. when ++ * they are enabled/disabled or marked pending and such. */ ++ ++ if (s->pending) ++ prioq_reshuffle(s->event->pending, s, &s->pending_index); ++ ++ if (s->prepare) ++ prioq_reshuffle(s->event->prepare, s, &s->prepare_index); ++} ++ ++static void event_source_time_prioq_reshuffle(sd_event_source *s) { ++ struct clock_data *d; ++ ++ assert(s); ++ assert(EVENT_SOURCE_IS_TIME(s->type)); ++ ++ /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, ++ * pending, enable state. Makes sure the two prioq's are ordered properly again. */ ++ assert_se(d = event_get_clock_data(s->event, s->type)); ++ prioq_reshuffle(d->earliest, s, &s->time.earliest_index); ++ prioq_reshuffle(d->latest, s, &s->time.latest_index); ++ d->needs_rearm = true; ++} ++ + static void source_disconnect(sd_event_source *s) { + sd_event *event; + +@@ -1052,16 +1079,8 @@ static int source_set_pending(sd_event_source *s, bool b) { + } else + assert_se(prioq_remove(s->event->pending, s, &s->pending_index)); + +- if (EVENT_SOURCE_IS_TIME(s->type)) { +- struct clock_data *d; +- +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; +- } ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ event_source_time_prioq_reshuffle(s); + + if (s->type == SOURCE_SIGNAL && !b) { + struct signal_data *d; +@@ -2215,11 +2234,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) + } else + s->priority = priority; + +- if (s->pending) +- prioq_reshuffle(s->event->pending, s, &s->pending_index); +- +- if (s->prepare) +- prioq_reshuffle(s->event->prepare, s, &s->prepare_index); ++ event_source_pp_prioq_reshuffle(s); + + if (s->type == SOURCE_EXIT) + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +@@ -2280,18 +2295,10 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: { +- struct clock_data *d; +- ++ case SOURCE_TIME_BOOTTIME_ALARM: + s->enabled = m; +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; ++ event_source_time_prioq_reshuffle(s); + break; +- } + + case SOURCE_SIGNAL: + s->enabled = m; +@@ -2346,18 +2353,10 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: { +- struct clock_data *d; +- ++ case SOURCE_TIME_BOOTTIME_ALARM: + s->enabled = m; +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; ++ event_source_time_prioq_reshuffle(s); + break; +- } + + case SOURCE_SIGNAL: + +@@ -2405,11 +2404,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + } + } + +- if (s->pending) +- prioq_reshuffle(s->event->pending, s, &s->pending_index); +- +- if (s->prepare) +- prioq_reshuffle(s->event->prepare, s, &s->prepare_index); ++ event_source_pp_prioq_reshuffle(s); + + return 0; + } +@@ -2425,7 +2420,6 @@ _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { + } + + _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { +- struct clock_data *d; + int r; + + assert_return(s, -EINVAL); +@@ -2439,13 +2433,7 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { + + s->time.next = usec; + +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; +- ++ event_source_time_prioq_reshuffle(s); + return 0; + } + +@@ -2460,7 +2448,6 @@ _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *use + } + + _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { +- struct clock_data *d; + int r; + + assert_return(s, -EINVAL); +@@ -2478,12 +2465,7 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec + + s->time.accuracy = usec; + +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; +- ++ event_source_time_prioq_reshuffle(s); + return 0; + } + +@@ -2773,9 +2755,7 @@ static int process_timer( + if (r < 0) + return r; + +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; ++ event_source_time_prioq_reshuffle(s); + } + + return 0; diff --git a/SOURCES/0547-sd-event-split-out-enable-and-disable-codepaths-from.patch b/SOURCES/0547-sd-event-split-out-enable-and-disable-codepaths-from.patch new file mode 100644 index 0000000..040b83f --- /dev/null +++ b/SOURCES/0547-sd-event-split-out-enable-and-disable-codepaths-from.patch @@ -0,0 +1,306 @@ +From d7ad6ad123200f562081ff09f7bed3c6d969ac0a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 23 Oct 2020 21:21:58 +0200 +Subject: [PATCH] sd-event: split out enable and disable codepaths from + sd_event_source_set_enabled() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So far half of sd_event_source_set_enabled() was doing enabling, the +other half was doing disabling. Let's split that into two separate +calls. + +(This also adds a new shortcut to sd_event_source_set_enabled(): if the +caller toggles between "ON" and "ONESHOT" we'll now shortcut this, since +the event source is already enabled in that case and shall remain +enabled.) + +This heavily borrows and is inspired from Michal Sekletár's #17284 +refactoring. + +(cherry picked from commit ddfde737b546c17e54182028153aa7f7e78804e3) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 227 +++++++++++++++-------------- + 1 file changed, 121 insertions(+), 106 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 47f99eb096..df5ed0dce8 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2260,152 +2260,167 @@ _public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { + return 0; + } + +-_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { ++static int event_source_disable(sd_event_source *s) { + int r; + +- assert_return(s, -EINVAL); +- assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); +- assert_return(!event_pid_changed(s->event), -ECHILD); ++ assert(s); ++ assert(s->enabled != SD_EVENT_OFF); + +- /* If we are dead anyway, we are fine with turning off +- * sources, but everything else needs to fail. */ +- if (s->event->state == SD_EVENT_FINISHED) +- return m == SD_EVENT_OFF ? 0 : -ESTALE; ++ /* Unset the pending flag when this event source is disabled */ ++ if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { ++ r = source_set_pending(s, false); ++ if (r < 0) ++ return r; ++ } + +- if (s->enabled == m) +- return 0; ++ s->enabled = SD_EVENT_OFF; + +- if (m == SD_EVENT_OFF) { ++ switch (s->type) { + +- /* Unset the pending flag when this event source is disabled */ +- if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { +- r = source_set_pending(s, false); +- if (r < 0) +- return r; +- } ++ case SOURCE_IO: ++ source_io_unregister(s); ++ break; + +- switch (s->type) { ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: ++ event_source_time_prioq_reshuffle(s); ++ break; + +- case SOURCE_IO: +- source_io_unregister(s); +- s->enabled = m; +- break; ++ case SOURCE_SIGNAL: ++ event_gc_signal_data(s->event, &s->priority, s->signal.sig); ++ break; + +- case SOURCE_TIME_REALTIME: +- case SOURCE_TIME_BOOTTIME: +- case SOURCE_TIME_MONOTONIC: +- case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: +- s->enabled = m; +- event_source_time_prioq_reshuffle(s); +- break; ++ case SOURCE_CHILD: ++ assert(s->event->n_enabled_child_sources > 0); ++ s->event->n_enabled_child_sources--; + +- case SOURCE_SIGNAL: +- s->enabled = m; ++ event_gc_signal_data(s->event, &s->priority, SIGCHLD); ++ break; + +- event_gc_signal_data(s->event, &s->priority, s->signal.sig); +- break; ++ case SOURCE_EXIT: ++ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); ++ break; + +- case SOURCE_CHILD: +- s->enabled = m; ++ case SOURCE_DEFER: ++ case SOURCE_POST: ++ case SOURCE_INOTIFY: ++ break; + +- assert(s->event->n_enabled_child_sources > 0); +- s->event->n_enabled_child_sources--; ++ default: ++ assert_not_reached("Wut? I shouldn't exist."); ++ } + +- event_gc_signal_data(s->event, &s->priority, SIGCHLD); +- break; ++ return 0; ++} + +- case SOURCE_EXIT: +- s->enabled = m; +- prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +- break; ++static int event_source_enable(sd_event_source *s, int m) { ++ int r; + +- case SOURCE_DEFER: +- case SOURCE_POST: +- case SOURCE_INOTIFY: +- s->enabled = m; +- break; ++ assert(s); ++ assert(IN_SET(m, SD_EVENT_ON, SD_EVENT_ONESHOT)); ++ assert(s->enabled == SD_EVENT_OFF); + +- default: +- assert_not_reached("Wut? I shouldn't exist."); +- } ++ /* Unset the pending flag when this event source is enabled */ ++ if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { ++ r = source_set_pending(s, false); ++ if (r < 0) ++ return r; ++ } + +- } else { ++ s->enabled = m; + +- /* Unset the pending flag when this event source is enabled */ +- if (s->enabled == SD_EVENT_OFF && !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { +- r = source_set_pending(s, false); +- if (r < 0) +- return r; ++ switch (s->type) { ++ ++ case SOURCE_IO: ++ r = source_io_register(s, m, s->io.events); ++ if (r < 0) { ++ s->enabled = SD_EVENT_OFF; ++ return r; + } + +- switch (s->type) { ++ break; + +- case SOURCE_IO: +- r = source_io_register(s, m, s->io.events); +- if (r < 0) +- return r; ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: ++ event_source_time_prioq_reshuffle(s); ++ break; + +- s->enabled = m; +- break; ++ case SOURCE_SIGNAL: ++ r = event_make_signal_data(s->event, s->signal.sig, NULL); ++ if (r < 0) { ++ s->enabled = SD_EVENT_OFF; ++ event_gc_signal_data(s->event, &s->priority, s->signal.sig); ++ return r; ++ } + +- case SOURCE_TIME_REALTIME: +- case SOURCE_TIME_BOOTTIME: +- case SOURCE_TIME_MONOTONIC: +- case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: +- s->enabled = m; +- event_source_time_prioq_reshuffle(s); +- break; ++ break; + +- case SOURCE_SIGNAL: ++ case SOURCE_CHILD: ++ s->event->n_enabled_child_sources++; + +- s->enabled = m; ++ r = event_make_signal_data(s->event, SIGCHLD, NULL); ++ if (r < 0) { ++ s->enabled = SD_EVENT_OFF; ++ s->event->n_enabled_child_sources--; ++ event_gc_signal_data(s->event, &s->priority, SIGCHLD); ++ return r; ++ } + +- r = event_make_signal_data(s->event, s->signal.sig, NULL); +- if (r < 0) { +- s->enabled = SD_EVENT_OFF; +- event_gc_signal_data(s->event, &s->priority, s->signal.sig); +- return r; +- } + +- break; ++ break; + +- case SOURCE_CHILD: ++ case SOURCE_EXIT: ++ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); ++ break; + +- if (s->enabled == SD_EVENT_OFF) +- s->event->n_enabled_child_sources++; ++ case SOURCE_DEFER: ++ case SOURCE_POST: ++ case SOURCE_INOTIFY: ++ break; + +- s->enabled = m; ++ default: ++ assert_not_reached("Wut? I shouldn't exist."); ++ } + +- r = event_make_signal_data(s->event, SIGCHLD, NULL); +- if (r < 0) { +- s->enabled = SD_EVENT_OFF; +- s->event->n_enabled_child_sources--; +- event_gc_signal_data(s->event, &s->priority, SIGCHLD); +- return r; +- } ++ return 0; ++} + +- break; ++_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { ++ int r; + +- case SOURCE_EXIT: +- s->enabled = m; +- prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +- break; ++ assert_return(s, -EINVAL); ++ assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); ++ assert_return(!event_pid_changed(s->event), -ECHILD); + +- case SOURCE_DEFER: +- case SOURCE_POST: +- case SOURCE_INOTIFY: +- s->enabled = m; +- break; ++ /* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */ ++ if (s->event->state == SD_EVENT_FINISHED) ++ return m == SD_EVENT_OFF ? 0 : -ESTALE; + +- default: +- assert_not_reached("Wut? I shouldn't exist."); ++ if (s->enabled == m) /* No change? */ ++ return 0; ++ ++ if (m == SD_EVENT_OFF) ++ r = event_source_disable(s); ++ else { ++ if (s->enabled != SD_EVENT_OFF) { ++ /* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the ++ * event source is already enabled after all. */ ++ s->enabled = m; ++ return 0; + } ++ ++ r = event_source_enable(s, m); + } ++ if (r < 0) ++ return r; + + event_source_pp_prioq_reshuffle(s); +- + return 0; + } + diff --git a/SOURCES/0548-sd-event-mention-that-two-debug-logged-events-are-ig.patch b/SOURCES/0548-sd-event-mention-that-two-debug-logged-events-are-ig.patch new file mode 100644 index 0000000..6ea67ca --- /dev/null +++ b/SOURCES/0548-sd-event-mention-that-two-debug-logged-events-are-ig.patch @@ -0,0 +1,37 @@ +From e8904b5b7957bfc9328f1ab8b6851c7b0d8920c9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 11:39:40 +0100 +Subject: [PATCH] sd-event: mention that two debug logged events are ignored + +(cherry picked from commit f80a5d6a86dc2346f406ee086ba179879afaab70) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index df5ed0dce8..0f507f18d8 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -596,8 +596,6 @@ static bool event_pid_changed(sd_event *e) { + } + + static void source_io_unregister(sd_event_source *s) { +- int r; +- + assert(s); + assert(s->type == SOURCE_IO); + +@@ -607,9 +605,8 @@ static void source_io_unregister(sd_event_source *s) { + if (!s->io.registered) + return; + +- r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); +- if (r < 0) +- log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", ++ if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0) ++ log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m", + strna(s->description), event_source_type_to_string(s->type)); + + s->io.registered = false; diff --git a/SOURCES/0549-sd-event-split-clock-data-allocation-out-of-sd_event.patch b/SOURCES/0549-sd-event-split-clock-data-allocation-out-of-sd_event.patch new file mode 100644 index 0000000..6e512af --- /dev/null +++ b/SOURCES/0549-sd-event-split-clock-data-allocation-out-of-sd_event.patch @@ -0,0 +1,71 @@ +From 6cc0022115afbac9ac66c456b140601d90271687 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 11:40:24 +0100 +Subject: [PATCH] sd-event: split clock data allocation out of + sd_event_add_time() + +Just some simple refactoring, that will make things easier for us later. +But it looks better this way even without the later function reuse. + +(cherry picked from commit 41c63f36c3352af8bebf03b6181f5d866431d0af) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 34 ++++++++++++++++++++---------- + 1 file changed, 23 insertions(+), 11 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 0f507f18d8..dc78dc7291 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -1232,6 +1232,28 @@ static int time_exit_callback(sd_event_source *s, uint64_t usec, void *userdata) + return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); + } + ++static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) { ++ int r; ++ ++ assert(d); ++ ++ if (d->fd < 0) { ++ r = event_setup_timer_fd(e, d, clock); ++ if (r < 0) ++ return r; ++ } ++ ++ r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); ++ if (r < 0) ++ return r; ++ ++ r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); ++ if (r < 0) ++ return r; ++ ++ return 0; ++} ++ + _public_ int sd_event_add_time( + sd_event *e, + sd_event_source **ret, +@@ -1265,20 +1287,10 @@ _public_ int sd_event_add_time( + d = event_get_clock_data(e, type); + assert(d); + +- r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); +- if (r < 0) +- return r; +- +- r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); ++ r = setup_clock_data(e, d, clock); + if (r < 0) + return r; + +- if (d->fd < 0) { +- r = event_setup_timer_fd(e, d, clock); +- if (r < 0) +- return r; +- } +- + s = source_new(e, !ret, type); + if (!s) + return -ENOMEM; diff --git a/SOURCES/0550-sd-event-split-out-code-to-add-remove-timer-event-so.patch b/SOURCES/0550-sd-event-split-out-code-to-add-remove-timer-event-so.patch new file mode 100644 index 0000000..0333f0d --- /dev/null +++ b/SOURCES/0550-sd-event-split-out-code-to-add-remove-timer-event-so.patch @@ -0,0 +1,112 @@ +From 88b2618e4de850060a1c5c22b049e6de0578fbb5 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 15:25:35 +0100 +Subject: [PATCH] sd-event: split out code to add/remove timer event sources to + earliest/latest prioq + +Just some refactoring that makes code prettier, and will come handy +later, because we can reuse these functions at more places. + +(cherry picked from commit 1e45e3fecc303e7ae9946220c742f69675e99c34) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 57 +++++++++++++++++++++--------- + 1 file changed, 41 insertions(+), 16 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index dc78dc7291..de9bb02059 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -913,6 +913,19 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) { + d->needs_rearm = true; + } + ++static void event_source_time_prioq_remove( ++ sd_event_source *s, ++ struct clock_data *d) { ++ ++ assert(s); ++ assert(d); ++ ++ prioq_remove(d->earliest, s, &s->time.earliest_index); ++ prioq_remove(d->latest, s, &s->time.latest_index); ++ s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; ++ d->needs_rearm = true; ++} ++ + static void source_disconnect(sd_event_source *s) { + sd_event *event; + +@@ -937,13 +950,8 @@ static void source_disconnect(sd_event_source *s) { + case SOURCE_TIME_REALTIME_ALARM: + case SOURCE_TIME_BOOTTIME_ALARM: { + struct clock_data *d; +- +- d = event_get_clock_data(s->event, s->type); +- assert(d); +- +- prioq_remove(d->earliest, s, &s->time.earliest_index); +- prioq_remove(d->latest, s, &s->time.latest_index); +- d->needs_rearm = true; ++ assert_se(d = event_get_clock_data(s->event, s->type)); ++ event_source_time_prioq_remove(s, d); + break; + } + +@@ -1254,6 +1262,30 @@ static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) + return 0; + } + ++static int event_source_time_prioq_put( ++ sd_event_source *s, ++ struct clock_data *d) { ++ ++ int r; ++ ++ assert(s); ++ assert(d); ++ ++ r = prioq_put(d->earliest, s, &s->time.earliest_index); ++ if (r < 0) ++ return r; ++ ++ r = prioq_put(d->latest, s, &s->time.latest_index); ++ if (r < 0) { ++ assert_se(prioq_remove(d->earliest, s, &s->time.earliest_index) > 0); ++ s->time.earliest_index = PRIOQ_IDX_NULL; ++ return r; ++ } ++ ++ d->needs_rearm = true; ++ return 0; ++} ++ + _public_ int sd_event_add_time( + sd_event *e, + sd_event_source **ret, +@@ -1284,8 +1316,7 @@ _public_ int sd_event_add_time( + if (!callback) + callback = time_exit_callback; + +- d = event_get_clock_data(e, type); +- assert(d); ++ assert_se(d = event_get_clock_data(e, type)); + + r = setup_clock_data(e, d, clock); + if (r < 0) +@@ -1302,13 +1333,7 @@ _public_ int sd_event_add_time( + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + +- d->needs_rearm = true; +- +- r = prioq_put(d->earliest, s, &s->time.earliest_index); +- if (r < 0) +- goto fail; +- +- r = prioq_put(d->latest, s, &s->time.latest_index); ++ r = event_source_time_prioq_put(s, d); + if (r < 0) + goto fail; + diff --git a/SOURCES/0551-sd-event-fix-delays-assert-brain-o-17790.patch b/SOURCES/0551-sd-event-fix-delays-assert-brain-o-17790.patch new file mode 100644 index 0000000..64afc46 --- /dev/null +++ b/SOURCES/0551-sd-event-fix-delays-assert-brain-o-17790.patch @@ -0,0 +1,29 @@ +From 1aae57f763cacbdeb10647c627cf307f79ad00ca Mon Sep 17 00:00:00 2001 +From: Vito Caputo +Date: Tue, 1 Dec 2020 00:26:54 -0800 +Subject: [PATCH] sd-event: fix delays assert brain-o (#17790) + +s/sizeof/ELEMENTSOF/ + +Bug introduced in 34b87517749caa4142b19eb3c63bdf349fafbc49. + +(cherry picked from commit cb9d621ebbfa30bbd620c17e143daeb0d78c12f0) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index de9bb02059..9d42157206 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -3586,7 +3586,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + this_run = now(CLOCK_MONOTONIC); + + l = u64log2(this_run - e->last_run); +- assert(l < sizeof(e->delays)); ++ assert(l < ELEMENTSOF(e->delays)); + e->delays[l]++; + + if (this_run - e->last_log >= 5*USEC_PER_SEC) { diff --git a/SOURCES/0552-sd-event-let-s-suffix-last_run-last_log-with-_usec.patch b/SOURCES/0552-sd-event-let-s-suffix-last_run-last_log-with-_usec.patch new file mode 100644 index 0000000..1393d01 --- /dev/null +++ b/SOURCES/0552-sd-event-let-s-suffix-last_run-last_log-with-_usec.patch @@ -0,0 +1,60 @@ +From 5b5a590c5a8bbaebbecf4ab4797334a09a870287 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 15:33:50 +0100 +Subject: [PATCH] sd-event: let's suffix last_run/last_log with "_usec" + +Otherwise it's a bit confusing what this is about: two timestamps. + +(cherry picked from commit e6a7bee538f6638c2d5ca2afc66bf47cba3f075c) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 9d42157206..88641879cc 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -301,7 +301,7 @@ struct sd_event { + + LIST_HEAD(sd_event_source, sources); + +- usec_t last_run, last_log; ++ usec_t last_run_usec, last_log_usec; + unsigned delays[sizeof(usec_t) * 8]; + }; + +@@ -3579,19 +3579,19 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + +- if (e->profile_delays && e->last_run) { ++ if (e->profile_delays && e->last_run_usec != 0) { + usec_t this_run; + unsigned l; + + this_run = now(CLOCK_MONOTONIC); + +- l = u64log2(this_run - e->last_run); ++ l = u64log2(this_run - e->last_run_usec); + assert(l < ELEMENTSOF(e->delays)); + e->delays[l]++; + +- if (this_run - e->last_log >= 5*USEC_PER_SEC) { ++ if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) { + event_log_delays(e); +- e->last_log = this_run; ++ e->last_log_usec = this_run; + } + } + +@@ -3601,7 +3601,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + r = sd_event_wait(e, timeout); + + if (e->profile_delays) +- e->last_run = now(CLOCK_MONOTONIC); ++ e->last_run_usec = now(CLOCK_MONOTONIC); + + if (r > 0) { + /* There's something now, then let's dispatch it */ diff --git a/SOURCES/0553-sd-event-refuse-running-default-event-loops-in-any-o.patch b/SOURCES/0553-sd-event-refuse-running-default-event-loops-in-any-o.patch new file mode 100644 index 0000000..95ad16f --- /dev/null +++ b/SOURCES/0553-sd-event-refuse-running-default-event-loops-in-any-o.patch @@ -0,0 +1,42 @@ +From 4c5fdbde7e745126f31542a70b45cc4faec094d2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 30 Oct 2019 20:26:50 +0100 +Subject: [PATCH] sd-event: refuse running default event loops in any other + thread than the one they are default for + +(cherry picked from commit e544601536ac13a288d7476f4400c7b0f22b7ea1) + +Related: #1819868 +--- + TODO | 1 - + src/libsystemd/sd-event/sd-event.c | 5 +++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/TODO b/TODO +index 8f78000089..3100e067d6 100644 +--- a/TODO ++++ b/TODO +@@ -581,7 +581,6 @@ Features: + - allow multiple signal handlers per signal? + - document chaining of signal handler for SIGCHLD and child handlers + - define more intervals where we will shift wakeup intervals around in, 1h, 6h, 24h, ... +- - generate a failure of a default event loop is executed out-of-thread + - maybe add support for inotify events (which we can do safely now, with O_PATH) + + * investigate endianness issues of UUID vs. GUID +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 88641879cc..537a0b81d4 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -3360,6 +3360,11 @@ _public_ int sd_event_prepare(sd_event *e) { + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + ++ /* Let's check that if we are a default event loop we are executed in the correct thread. We only do ++ * this check here once, since gettid() is typically not cached, and thus want to minimize ++ * syscalls */ ++ assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); ++ + if (e->exit_requested) + goto pending; + diff --git a/SOURCES/0554-sd-event-ref-event-loop-while-in-sd_event_prepare-ot.patch b/SOURCES/0554-sd-event-ref-event-loop-while-in-sd_event_prepare-ot.patch new file mode 100644 index 0000000..4824f09 --- /dev/null +++ b/SOURCES/0554-sd-event-ref-event-loop-while-in-sd_event_prepare-ot.patch @@ -0,0 +1,92 @@ +From 441684c6c961edec1391562fb2f48ff997a6169e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 15:38:00 +0100 +Subject: [PATCH] sd-event: ref event loop while in sd_event_prepare() ot + sd_event_run() + +sd_event_prepare() invokes callbacks that might drop the last user ref +on our event loop. Let's make sure we keep an explicit ref around it, so +that we won't end up with an invalid pointer. Similar in sd_event_run(). + +Basically, any function that is publically callable that might end up +invoking callbacks should ref the relevant objects to be protected +against callbacks destroying these objects while we still want to access +them. We did this correctly in sd_event_dispatch() and sd_event_loop(), +but these are not the only ones which are callable from the outside. + +(cherry picked from commit f814c871e65df8552a055dd887bc94b074037833) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 537a0b81d4..be1e6e5f53 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -3256,7 +3256,6 @@ static int event_prepare(sd_event *e) { + + static int dispatch_exit(sd_event *e) { + sd_event_source *p; +- _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + int r; + + assert(e); +@@ -3267,7 +3266,7 @@ static int dispatch_exit(sd_event *e) { + return 0; + } + +- ref = sd_event_ref(e); ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + e->iteration++; + e->state = SD_EVENT_EXITING; + r = source_dispatch(p); +@@ -3365,6 +3364,9 @@ _public_ int sd_event_prepare(sd_event *e) { + * syscalls */ + assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); + ++ /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); ++ + if (e->exit_requested) + goto pending; + +@@ -3549,9 +3551,8 @@ _public_ int sd_event_dispatch(sd_event *e) { + + p = event_next_pending(e); + if (p) { +- _cleanup_(sd_event_unrefp) sd_event *ref = NULL; ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + +- ref = sd_event_ref(e); + e->state = SD_EVENT_RUNNING; + r = source_dispatch(p); + e->state = SD_EVENT_INITIAL; +@@ -3600,6 +3601,9 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + } + } + ++ /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); ++ + r = sd_event_prepare(e); + if (r == 0) + /* There was nothing? Then wait... */ +@@ -3621,7 +3625,6 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { + } + + _public_ int sd_event_loop(sd_event *e) { +- _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + int r; + + assert_return(e, -EINVAL); +@@ -3629,7 +3632,7 @@ _public_ int sd_event_loop(sd_event *e) { + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + +- ref = sd_event_ref(e); ++ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + + while (e->state != SD_EVENT_FINISHED) { + r = sd_event_run(e, (uint64_t) -1); diff --git a/SOURCES/0555-sd-event-follow-coding-style-with-naming-return-para.patch b/SOURCES/0555-sd-event-follow-coding-style-with-naming-return-para.patch new file mode 100644 index 0000000..ab585e0 --- /dev/null +++ b/SOURCES/0555-sd-event-follow-coding-style-with-naming-return-para.patch @@ -0,0 +1,35 @@ +From 846b1dd75e626ad2e2483673eea65774edea9016 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 17:47:16 +0100 +Subject: [PATCH] sd-event: follow coding style with naming return parameter + +(cherry picked from commit cad143a8f26976a23e634d5e1ecfb7d7ba75c3bf) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index be1e6e5f53..739296abcf 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2285,13 +2285,14 @@ fail: + return r; + } + +-_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { ++_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { + assert_return(s, -EINVAL); +- assert_return(m, -EINVAL); + assert_return(!event_pid_changed(s->event), -ECHILD); + +- *m = s->enabled; +- return 0; ++ if (ret) ++ *ret = s->enabled; ++ ++ return s->enabled != SD_EVENT_OFF; + } + + static int event_source_disable(sd_event_source *s) { diff --git a/SOURCES/0556-sd-event-remove-earliest_index-latest_index-into-com.patch b/SOURCES/0556-sd-event-remove-earliest_index-latest_index-into-com.patch new file mode 100644 index 0000000..7fb9b47 --- /dev/null +++ b/SOURCES/0556-sd-event-remove-earliest_index-latest_index-into-com.patch @@ -0,0 +1,98 @@ +From 97f599bf57fdaee688ae5750e9b2b2587e2b597a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 17:49:27 +0100 +Subject: [PATCH] sd-event: remove earliest_index/latest_index into common part + of event source objects + +So far we used these fields to organize the earliest/latest timer event +priority queue. In a follow-up commit we want to introduce ratelimiting +to event sources, at which point we want any kind of event source to be +able to trigger time wakeups, and hence they all need to be included in +the earliest/latest prioqs. Thus, in preparation let's make this +generic. + +No change in behaviour, just some shifting around of struct members from +the type-specific to the generic part. + +(cherry picked from commit f41315fceb5208c496145cda2d6c865a5458ce44) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 739296abcf..34b42c298f 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -107,6 +107,9 @@ struct sd_event_source { + + LIST_FIELDS(sd_event_source, sources); + ++ unsigned earliest_index; ++ unsigned latest_index; ++ + union { + struct { + sd_event_io_handler_t callback; +@@ -119,8 +122,6 @@ struct sd_event_source { + struct { + sd_event_time_handler_t callback; + usec_t next, accuracy; +- unsigned earliest_index; +- unsigned latest_index; + } time; + struct { + sd_event_signal_handler_t callback; +@@ -908,8 +909,8 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) { + /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, + * pending, enable state. Makes sure the two prioq's are ordered properly again. */ + assert_se(d = event_get_clock_data(s->event, s->type)); +- prioq_reshuffle(d->earliest, s, &s->time.earliest_index); +- prioq_reshuffle(d->latest, s, &s->time.latest_index); ++ prioq_reshuffle(d->earliest, s, &s->earliest_index); ++ prioq_reshuffle(d->latest, s, &s->latest_index); + d->needs_rearm = true; + } + +@@ -920,9 +921,9 @@ static void event_source_time_prioq_remove( + assert(s); + assert(d); + +- prioq_remove(d->earliest, s, &s->time.earliest_index); +- prioq_remove(d->latest, s, &s->time.latest_index); +- s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; ++ prioq_remove(d->earliest, s, &s->earliest_index); ++ prioq_remove(d->latest, s, &s->latest_index); ++ s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; + d->needs_rearm = true; + } + +@@ -1271,14 +1272,14 @@ static int event_source_time_prioq_put( + assert(s); + assert(d); + +- r = prioq_put(d->earliest, s, &s->time.earliest_index); ++ r = prioq_put(d->earliest, s, &s->earliest_index); + if (r < 0) + return r; + +- r = prioq_put(d->latest, s, &s->time.latest_index); ++ r = prioq_put(d->latest, s, &s->latest_index); + if (r < 0) { +- assert_se(prioq_remove(d->earliest, s, &s->time.earliest_index) > 0); +- s->time.earliest_index = PRIOQ_IDX_NULL; ++ assert_se(prioq_remove(d->earliest, s, &s->earliest_index) > 0); ++ s->earliest_index = PRIOQ_IDX_NULL; + return r; + } + +@@ -1329,7 +1330,7 @@ _public_ int sd_event_add_time( + s->time.next = usec; + s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy; + s->time.callback = callback; +- s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; ++ s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + diff --git a/SOURCES/0557-sd-event-update-state-at-the-end-in-event_source_ena.patch b/SOURCES/0557-sd-event-update-state-at-the-end-in-event_source_ena.patch new file mode 100644 index 0000000..e0a2145 --- /dev/null +++ b/SOURCES/0557-sd-event-update-state-at-the-end-in-event_source_ena.patch @@ -0,0 +1,116 @@ +From deb9e6ad3a1d7cfbc3b53d1e74cda6ae398a90fd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 10 Nov 2020 10:38:37 +0100 +Subject: [PATCH] sd-event: update state at the end in event_source_enable + +Coverity in CID#1435966 was complaining that s->enabled is not "restored" in +all cases. But the code was actually correct, since it should only be +"restored" in the error paths. But let's still make this prettier by not setting +the state before all operations that may fail are done. + +We need to set .enabled for the prioq reshuffling operations, so move those down. + +No functional change intended. + +(cherry picked from commit d2eafe61ca07f8300dc741a0491a914213fa2b6b) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 51 +++++++++++++++++------------- + 1 file changed, 29 insertions(+), 22 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 34b42c298f..0cfba8fb39 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2352,11 +2352,11 @@ static int event_source_disable(sd_event_source *s) { + return 0; + } + +-static int event_source_enable(sd_event_source *s, int m) { ++static int event_source_enable(sd_event_source *s, int enable) { + int r; + + assert(s); +- assert(IN_SET(m, SD_EVENT_ON, SD_EVENT_ONESHOT)); ++ assert(IN_SET(enable, SD_EVENT_ON, SD_EVENT_ONESHOT)); + assert(s->enabled == SD_EVENT_OFF); + + /* Unset the pending flag when this event source is enabled */ +@@ -2366,31 +2366,16 @@ static int event_source_enable(sd_event_source *s, int m) { + return r; + } + +- s->enabled = m; +- + switch (s->type) { +- + case SOURCE_IO: +- r = source_io_register(s, m, s->io.events); +- if (r < 0) { +- s->enabled = SD_EVENT_OFF; ++ r = source_io_register(s, enable, s->io.events); ++ if (r < 0) + return r; +- } +- +- break; +- +- case SOURCE_TIME_REALTIME: +- case SOURCE_TIME_BOOTTIME: +- case SOURCE_TIME_MONOTONIC: +- case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: +- event_source_time_prioq_reshuffle(s); + break; + + case SOURCE_SIGNAL: + r = event_make_signal_data(s->event, s->signal.sig, NULL); + if (r < 0) { +- s->enabled = SD_EVENT_OFF; + event_gc_signal_data(s->event, &s->priority, s->signal.sig); + return r; + } +@@ -2411,10 +2396,12 @@ static int event_source_enable(sd_event_source *s, int m) { + + break; + ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: + case SOURCE_EXIT: +- prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +- break; +- + case SOURCE_DEFER: + case SOURCE_POST: + case SOURCE_INOTIFY: +@@ -2424,6 +2411,26 @@ static int event_source_enable(sd_event_source *s, int m) { + assert_not_reached("Wut? I shouldn't exist."); + } + ++ s->enabled = enable; ++ ++ /* Non-failing operations below */ ++ switch (s->type) { ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: ++ event_source_time_prioq_reshuffle(s); ++ break; ++ ++ case SOURCE_EXIT: ++ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); ++ break; ++ ++ default: ++ break; ++ } ++ + return 0; + } + diff --git a/SOURCES/0558-sd-event-increase-n_enabled_child_sources-just-once.patch b/SOURCES/0558-sd-event-increase-n_enabled_child_sources-just-once.patch new file mode 100644 index 0000000..2a41752 --- /dev/null +++ b/SOURCES/0558-sd-event-increase-n_enabled_child_sources-just-once.patch @@ -0,0 +1,36 @@ +From 188465c472996b426a1f22a9fc46d031b722c3b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 10 Nov 2020 12:57:34 +0100 +Subject: [PATCH] sd-event: increase n_enabled_child_sources just once + +Neither source_child_pidfd_register() nor event_make_signal_data() look at +n_enabled_child_sources. + +(cherry picked from commit ac9f2640cb9c107b43f47bba7e068d3b92b5337b) + +Related: #1819868 +--- + src/libsystemd/sd-event/sd-event.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 0cfba8fb39..d18ce28a92 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2383,8 +2383,6 @@ static int event_source_enable(sd_event_source *s, int enable) { + break; + + case SOURCE_CHILD: +- s->event->n_enabled_child_sources++; +- + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; +@@ -2393,6 +2391,7 @@ static int event_source_enable(sd_event_source *s, int enable) { + return r; + } + ++ s->event->n_enabled_child_sources++; + + break; + diff --git a/SOURCES/0559-sd-event-add-ability-to-ratelimit-event-sources.patch b/SOURCES/0559-sd-event-add-ability-to-ratelimit-event-sources.patch new file mode 100644 index 0000000..b8c20d0 --- /dev/null +++ b/SOURCES/0559-sd-event-add-ability-to-ratelimit-event-sources.patch @@ -0,0 +1,858 @@ +From 395eb7753a9772f505102fbbe3ba3261b57abbe9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 23 Nov 2020 18:02:40 +0100 +Subject: [PATCH] sd-event: add ability to ratelimit event sources + +Let's a concept of "rate limiting" to event sources: if specific event +sources fire too often in some time interval temporarily take them +offline, and take them back online once the interval passed. + +This is a simple scheme of avoiding starvation of event sources if some +event source fires too often. + +This introduces the new conceptual states of "offline" and "online" for +event sources: an event source is "online" only when enabled *and* not +ratelimited, and offline in all other cases. An event source that is +online hence has its fds registered in the epoll, its signals in the +signalfd and so on. + +(cherry picked from commit b6d5481b3d9f7c9b1198ab54b54326ec73e855bf) + +Related: #1819868 +--- + src/basic/ratelimit.h | 8 + + src/libsystemd/libsystemd.sym | 7 + + src/libsystemd/sd-event/sd-event.c | 433 +++++++++++++++++++++++------ + src/systemd/sd-event.h | 3 + + 4 files changed, 369 insertions(+), 82 deletions(-) + +diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h +index de91def28d..0012b49935 100644 +--- a/src/basic/ratelimit.h ++++ b/src/basic/ratelimit.h +@@ -38,3 +38,11 @@ typedef struct RateLimit { + } while (false) + + bool ratelimit_below(RateLimit *r); ++ ++static inline void ratelimit_reset(RateLimit *rl) { ++ rl->num = rl->begin = 0; ++} ++ ++static inline bool ratelimit_configured(RateLimit *rl) { ++ return rl->interval > 0 && rl->burst > 0; ++} +diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym +index 778e88a16c..149d2e7b82 100644 +--- a/src/libsystemd/libsystemd.sym ++++ b/src/libsystemd/libsystemd.sym +@@ -572,3 +572,10 @@ global: + sd_bus_enqueue_for_read; + sd_event_source_disable_unref; + } LIBSYSTEMD_238; ++ ++LIBSYSTEMD_248 { ++global: ++ sd_event_source_set_ratelimit; ++ sd_event_source_get_ratelimit; ++ sd_event_source_is_ratelimited; ++} LIBSYSTEMD_239; +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index d18ce28a92..be912d94e3 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -19,6 +19,7 @@ + #include "missing.h" + #include "prioq.h" + #include "process-util.h" ++#include "ratelimit.h" + #include "set.h" + #include "signal-util.h" + #include "string-table.h" +@@ -46,6 +47,7 @@ typedef enum EventSourceType { + _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 + } EventSourceType; + ++ + static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { + [SOURCE_IO] = "io", + [SOURCE_TIME_REALTIME] = "realtime", +@@ -76,7 +78,25 @@ typedef enum WakeupType { + _WAKEUP_TYPE_INVALID = -1, + } WakeupType; + +-#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM) ++#define EVENT_SOURCE_IS_TIME(t) \ ++ IN_SET((t), \ ++ SOURCE_TIME_REALTIME, \ ++ SOURCE_TIME_BOOTTIME, \ ++ SOURCE_TIME_MONOTONIC, \ ++ SOURCE_TIME_REALTIME_ALARM, \ ++ SOURCE_TIME_BOOTTIME_ALARM) ++ ++#define EVENT_SOURCE_CAN_RATE_LIMIT(t) \ ++ IN_SET((t), \ ++ SOURCE_IO, \ ++ SOURCE_TIME_REALTIME, \ ++ SOURCE_TIME_BOOTTIME, \ ++ SOURCE_TIME_MONOTONIC, \ ++ SOURCE_TIME_REALTIME_ALARM, \ ++ SOURCE_TIME_BOOTTIME_ALARM, \ ++ SOURCE_SIGNAL, \ ++ SOURCE_DEFER, \ ++ SOURCE_INOTIFY) + + struct inode_data; + +@@ -96,6 +116,7 @@ struct sd_event_source { + bool pending:1; + bool dispatching:1; + bool floating:1; ++ bool ratelimited:1; + + int64_t priority; + unsigned pending_index; +@@ -107,6 +128,10 @@ struct sd_event_source { + + LIST_FIELDS(sd_event_source, sources); + ++ RateLimit rate_limit; ++ ++ /* These are primarily fields relevant for time event sources, but since any event source can ++ * effectively become one when rate-limited, this is part of the common fields. */ + unsigned earliest_index; + unsigned latest_index; + +@@ -266,7 +291,7 @@ struct sd_event { + Hashmap *signal_data; /* indexed by priority */ + + Hashmap *child_sources; +- unsigned n_enabled_child_sources; ++ unsigned n_online_child_sources; + + Set *post_sources; + +@@ -311,12 +336,23 @@ static thread_local sd_event *default_event = NULL; + static void source_disconnect(sd_event_source *s); + static void event_gc_inode_data(sd_event *e, struct inode_data *d); + ++static bool event_source_is_online(sd_event_source *s) { ++ assert(s); ++ return s->enabled != SD_EVENT_OFF && !s->ratelimited; ++} ++ ++static bool event_source_is_offline(sd_event_source *s) { ++ assert(s); ++ return s->enabled == SD_EVENT_OFF || s->ratelimited; ++} ++ + static sd_event *event_resolve(sd_event *e) { + return e == SD_EVENT_DEFAULT ? default_event : e; + } + + static int pending_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; ++ int r; + + assert(x->pending); + assert(y->pending); +@@ -327,23 +363,23 @@ static int pending_prioq_compare(const void *a, const void *b) { + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + ++ /* Non rate-limited ones first. */ ++ r = CMP(!!x->ratelimited, !!y->ratelimited); ++ if (r != 0) ++ return r; ++ + /* Lower priority values first */ +- if (x->priority < y->priority) +- return -1; +- if (x->priority > y->priority) +- return 1; ++ r = CMP(x->priority, y->priority); ++ if (r != 0) ++ return r; + + /* Older entries first */ +- if (x->pending_iteration < y->pending_iteration) +- return -1; +- if (x->pending_iteration > y->pending_iteration) +- return 1; +- +- return 0; ++ return CMP(x->pending_iteration, y->pending_iteration); + } + + static int prepare_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; ++ int r; + + assert(x->prepare); + assert(y->prepare); +@@ -354,29 +390,46 @@ static int prepare_prioq_compare(const void *a, const void *b) { + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + ++ /* Non rate-limited ones first. */ ++ r = CMP(!!x->ratelimited, !!y->ratelimited); ++ if (r != 0) ++ return r; ++ + /* Move most recently prepared ones last, so that we can stop + * preparing as soon as we hit one that has already been + * prepared in the current iteration */ +- if (x->prepare_iteration < y->prepare_iteration) +- return -1; +- if (x->prepare_iteration > y->prepare_iteration) +- return 1; ++ r = CMP(x->prepare_iteration, y->prepare_iteration); ++ if (r != 0) ++ return r; + + /* Lower priority values first */ +- if (x->priority < y->priority) +- return -1; +- if (x->priority > y->priority) +- return 1; ++ return CMP(x->priority, y->priority); ++} + +- return 0; ++static usec_t time_event_source_next(const sd_event_source *s) { ++ assert(s); ++ ++ /* We have two kinds of event sources that have elapsation times associated with them: the actual ++ * time based ones and the ones for which a ratelimit can be in effect (where we want to be notified ++ * once the ratelimit time window ends). Let's return the next elapsing time depending on what we are ++ * looking at here. */ ++ ++ if (s->ratelimited) { /* If rate-limited the next elapsation is when the ratelimit time window ends */ ++ assert(s->rate_limit.begin != 0); ++ assert(s->rate_limit.interval != 0); ++ return usec_add(s->rate_limit.begin, s->rate_limit.interval); ++ } ++ ++ /* Otherwise this must be a time event source, if not ratelimited */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ return s->time.next; ++ ++ return USEC_INFINITY; + } + + static int earliest_time_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + +- assert(EVENT_SOURCE_IS_TIME(x->type)); +- assert(x->type == y->type); +- + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; +@@ -390,24 +443,30 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { + return 1; + + /* Order by time */ +- if (x->time.next < y->time.next) +- return -1; +- if (x->time.next > y->time.next) +- return 1; +- +- return 0; ++ return CMP(time_event_source_next(x), time_event_source_next(y)); + } + + static usec_t time_event_source_latest(const sd_event_source *s) { +- return usec_add(s->time.next, s->time.accuracy); ++ assert(s); ++ ++ if (s->ratelimited) { /* For ratelimited stuff the earliest and the latest time shall actually be the ++ * same, as we should avoid adding additional inaccuracy on an inaccuracy time ++ * window */ ++ assert(s->rate_limit.begin != 0); ++ assert(s->rate_limit.interval != 0); ++ return usec_add(s->rate_limit.begin, s->rate_limit.interval); ++ } ++ ++ /* Must be a time event source, if not ratelimited */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ return usec_add(s->time.next, s->time.accuracy); ++ ++ return USEC_INFINITY; + } + + static int latest_time_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + +- assert(EVENT_SOURCE_IS_TIME(x->type)); +- assert(x->type == y->type); +- + /* Enabled ones first */ + if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) + return -1; +@@ -852,12 +911,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) + * the signalfd for it. */ + + if (sig == SIGCHLD && +- e->n_enabled_child_sources > 0) ++ e->n_online_child_sources > 0) + return; + + if (e->signal_sources && + e->signal_sources[sig] && +- e->signal_sources[sig]->enabled != SD_EVENT_OFF) ++ event_source_is_online(e->signal_sources[sig])) + return; + + /* +@@ -904,11 +963,17 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) { + struct clock_data *d; + + assert(s); +- assert(EVENT_SOURCE_IS_TIME(s->type)); + + /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, + * pending, enable state. Makes sure the two prioq's are ordered properly again. */ +- assert_se(d = event_get_clock_data(s->event, s->type)); ++ ++ if (s->ratelimited) ++ d = &s->event->monotonic; ++ else { ++ assert(EVENT_SOURCE_IS_TIME(s->type)); ++ assert_se(d = event_get_clock_data(s->event, s->type)); ++ } ++ + prioq_reshuffle(d->earliest, s, &s->earliest_index); + prioq_reshuffle(d->latest, s, &s->latest_index); + d->needs_rearm = true; +@@ -949,12 +1014,18 @@ static void source_disconnect(sd_event_source *s) { + case SOURCE_TIME_BOOTTIME: + case SOURCE_TIME_MONOTONIC: + case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: { +- struct clock_data *d; +- assert_se(d = event_get_clock_data(s->event, s->type)); +- event_source_time_prioq_remove(s, d); ++ case SOURCE_TIME_BOOTTIME_ALARM: ++ /* Only remove this event source from the time event source here if it is not ratelimited. If ++ * it is ratelimited, we'll remove it below, separately. Why? Because the clock used might ++ * differ: ratelimiting always uses CLOCK_MONOTONIC, but timer events might use any clock */ ++ ++ if (!s->ratelimited) { ++ struct clock_data *d; ++ assert_se(d = event_get_clock_data(s->event, s->type)); ++ event_source_time_prioq_remove(s, d); ++ } ++ + break; +- } + + case SOURCE_SIGNAL: + if (s->signal.sig > 0) { +@@ -969,9 +1040,9 @@ static void source_disconnect(sd_event_source *s) { + + case SOURCE_CHILD: + if (s->child.pid > 0) { +- if (s->enabled != SD_EVENT_OFF) { +- assert(s->event->n_enabled_child_sources > 0); +- s->event->n_enabled_child_sources--; ++ if (event_source_is_online(s)) { ++ assert(s->event->n_online_child_sources > 0); ++ s->event->n_online_child_sources--; + } + + (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); +@@ -1037,6 +1108,9 @@ static void source_disconnect(sd_event_source *s) { + if (s->prepare) + prioq_remove(s->event->prepare, s, &s->prepare_index); + ++ if (s->ratelimited) ++ event_source_time_prioq_remove(s, &s->event->monotonic); ++ + event = s->event; + + s->type = _SOURCE_EVENT_SOURCE_TYPE_INVALID; +@@ -1458,11 +1532,11 @@ _public_ int sd_event_add_child( + return r; + } + +- e->n_enabled_child_sources++; ++ e->n_online_child_sources++; + + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { +- e->n_enabled_child_sources--; ++ e->n_online_child_sources--; + source_free(s); + return r; + } +@@ -2079,7 +2153,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { + if (s->io.fd == fd) + return 0; + +- if (s->enabled == SD_EVENT_OFF) { ++ if (event_source_is_offline(s)) { + s->io.fd = fd; + s->io.registered = false; + } else { +@@ -2146,7 +2220,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) + if (r < 0) + return r; + +- if (s->enabled != SD_EVENT_OFF) { ++ if (event_source_is_online(s)) { + r = source_io_register(s, s->enabled, events); + if (r < 0) + return r; +@@ -2249,7 +2323,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) + + event_gc_inode_data(s->event, old_inode_data); + +- } else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) { ++ } else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) { + struct signal_data *old, *d; + + /* Move us from the signalfd belonging to the old +@@ -2296,20 +2370,29 @@ _public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { + return s->enabled != SD_EVENT_OFF; + } + +-static int event_source_disable(sd_event_source *s) { ++static int event_source_offline( ++ sd_event_source *s, ++ int enabled, ++ bool ratelimited) { ++ ++ bool was_offline; + int r; + + assert(s); +- assert(s->enabled != SD_EVENT_OFF); ++ assert(enabled == SD_EVENT_OFF || ratelimited); + + /* Unset the pending flag when this event source is disabled */ +- if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { ++ if (s->enabled != SD_EVENT_OFF && ++ enabled == SD_EVENT_OFF && ++ !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } + +- s->enabled = SD_EVENT_OFF; ++ was_offline = event_source_is_offline(s); ++ s->enabled = enabled; ++ s->ratelimited = ratelimited; + + switch (s->type) { + +@@ -2330,8 +2413,10 @@ static int event_source_disable(sd_event_source *s) { + break; + + case SOURCE_CHILD: +- assert(s->event->n_enabled_child_sources > 0); +- s->event->n_enabled_child_sources--; ++ if (!was_offline) { ++ assert(s->event->n_online_child_sources > 0); ++ s->event->n_online_child_sources--; ++ } + + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; +@@ -2349,26 +2434,42 @@ static int event_source_disable(sd_event_source *s) { + assert_not_reached("Wut? I shouldn't exist."); + } + +- return 0; ++ return 1; + } + +-static int event_source_enable(sd_event_source *s, int enable) { ++static int event_source_online( ++ sd_event_source *s, ++ int enabled, ++ bool ratelimited) { ++ ++ bool was_online; + int r; + + assert(s); +- assert(IN_SET(enable, SD_EVENT_ON, SD_EVENT_ONESHOT)); +- assert(s->enabled == SD_EVENT_OFF); ++ assert(enabled != SD_EVENT_OFF || !ratelimited); + + /* Unset the pending flag when this event source is enabled */ +- if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { ++ if (s->enabled == SD_EVENT_OFF && ++ enabled != SD_EVENT_OFF && ++ !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) + return r; + } + ++ /* Are we really ready for onlining? */ ++ if (enabled == SD_EVENT_OFF || ratelimited) { ++ /* Nope, we are not ready for onlining, then just update the precise state and exit */ ++ s->enabled = enabled; ++ s->ratelimited = ratelimited; ++ return 0; ++ } ++ ++ was_online = event_source_is_online(s); ++ + switch (s->type) { + case SOURCE_IO: +- r = source_io_register(s, enable, s->io.events); ++ r = source_io_register(s, enabled, s->io.events); + if (r < 0) + return r; + break; +@@ -2386,13 +2487,13 @@ static int event_source_enable(sd_event_source *s, int enable) { + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; +- s->event->n_enabled_child_sources--; ++ s->event->n_online_child_sources--; + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + return r; + } + +- s->event->n_enabled_child_sources++; +- ++ if (!was_online) ++ s->event->n_online_child_sources++; + break; + + case SOURCE_TIME_REALTIME: +@@ -2410,7 +2511,8 @@ static int event_source_enable(sd_event_source *s, int enable) { + assert_not_reached("Wut? I shouldn't exist."); + } + +- s->enabled = enable; ++ s->enabled = enabled; ++ s->ratelimited = ratelimited; + + /* Non-failing operations below */ + switch (s->type) { +@@ -2430,7 +2532,7 @@ static int event_source_enable(sd_event_source *s, int enable) { + break; + } + +- return 0; ++ return 1; + } + + _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { +@@ -2448,7 +2550,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + return 0; + + if (m == SD_EVENT_OFF) +- r = event_source_disable(s); ++ r = event_source_offline(s, m, s->ratelimited); + else { + if (s->enabled != SD_EVENT_OFF) { + /* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the +@@ -2457,7 +2559,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { + return 0; + } + +- r = event_source_enable(s, m); ++ r = event_source_online(s, m, s->ratelimited); + } + if (r < 0) + return r; +@@ -2605,6 +2707,96 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) + return ret; + } + ++static int event_source_enter_ratelimited(sd_event_source *s) { ++ int r; ++ ++ assert(s); ++ ++ /* When an event source becomes ratelimited, we place it in the CLOCK_MONOTONIC priority queue, with ++ * the end of the rate limit time window, much as if it was a timer event source. */ ++ ++ if (s->ratelimited) ++ return 0; /* Already ratelimited, this is a NOP hence */ ++ ++ /* Make sure we can install a CLOCK_MONOTONIC event further down. */ ++ r = setup_clock_data(s->event, &s->event->monotonic, CLOCK_MONOTONIC); ++ if (r < 0) ++ return r; ++ ++ /* Timer event sources are already using the earliest/latest queues for the timer scheduling. Let's ++ * first remove them from the prioq appropriate for their own clock, so that we can use the prioq ++ * fields of the event source then for adding it to the CLOCK_MONOTONIC prioq instead. */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); ++ ++ /* Now, let's add the event source to the monotonic clock instead */ ++ r = event_source_time_prioq_put(s, &s->event->monotonic); ++ if (r < 0) ++ goto fail; ++ ++ /* And let's take the event source officially offline */ ++ r = event_source_offline(s, s->enabled, /* ratelimited= */ true); ++ if (r < 0) { ++ event_source_time_prioq_remove(s, &s->event->monotonic); ++ goto fail; ++ } ++ ++ event_source_pp_prioq_reshuffle(s); ++ ++ log_debug("Event source %p (%s) entered rate limit state.", s, strna(s->description)); ++ return 0; ++ ++fail: ++ /* Reinstall time event sources in the priority queue as before. This shouldn't fail, since the queue ++ * space for it should already be allocated. */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ assert_se(event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)) >= 0); ++ ++ return r; ++} ++ ++static int event_source_leave_ratelimit(sd_event_source *s) { ++ int r; ++ ++ assert(s); ++ ++ if (!s->ratelimited) ++ return 0; ++ ++ /* Let's take the event source out of the monotonic prioq first. */ ++ event_source_time_prioq_remove(s, &s->event->monotonic); ++ ++ /* Let's then add the event source to its native clock prioq again — if this is a timer event source */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) { ++ r = event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)); ++ if (r < 0) ++ goto fail; ++ } ++ ++ /* Let's try to take it online again. */ ++ r = event_source_online(s, s->enabled, /* ratelimited= */ false); ++ if (r < 0) { ++ /* Do something roughly sensible when this failed: undo the two prioq ops above */ ++ if (EVENT_SOURCE_IS_TIME(s->type)) ++ event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); ++ ++ goto fail; ++ } ++ ++ event_source_pp_prioq_reshuffle(s); ++ ratelimit_reset(&s->rate_limit); ++ ++ log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description)); ++ return 0; ++ ++fail: ++ /* Do something somewhat reasonable when we cannot move an event sources out of ratelimited mode: ++ * simply put it back in it, maybe we can then process it more successfully next iteration. */ ++ assert_se(event_source_time_prioq_put(s, &s->event->monotonic) >= 0); ++ ++ return r; ++} ++ + static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { + usec_t c; + assert(e); +@@ -2703,7 +2895,7 @@ static int event_arm_timer( + d->needs_rearm = false; + + a = prioq_peek(d->earliest); +- if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) { ++ if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) { + + if (d->fd < 0) + return 0; +@@ -2723,7 +2915,7 @@ static int event_arm_timer( + b = prioq_peek(d->latest); + assert_se(b && b->enabled != SD_EVENT_OFF); + +- t = sleep_between(e, a->time.next, time_event_source_latest(b)); ++ t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b)); + if (d->next == t) + return 0; + +@@ -2802,10 +2994,22 @@ static int process_timer( + + for (;;) { + s = prioq_peek(d->earliest); +- if (!s || +- s->time.next > n || +- s->enabled == SD_EVENT_OFF || +- s->pending) ++ if (!s || time_event_source_next(s) > n) ++ break; ++ ++ if (s->ratelimited) { ++ /* This is an event sources whose ratelimit window has ended. Let's turn it on ++ * again. */ ++ assert(s->ratelimited); ++ ++ r = event_source_leave_ratelimit(s); ++ if (r < 0) ++ return r; ++ ++ continue; ++ } ++ ++ if (s->enabled == SD_EVENT_OFF || s->pending) + break; + + r = source_set_pending(s, true); +@@ -2851,7 +3055,7 @@ static int process_child(sd_event *e) { + if (s->pending) + continue; + +- if (s->enabled == SD_EVENT_OFF) ++ if (event_source_is_offline(s)) + continue; + + zero(s->child.siginfo); +@@ -3024,7 +3228,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { + + LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { + +- if (s->enabled == SD_EVENT_OFF) ++ if (event_source_is_offline(s)) + continue; + + r = source_set_pending(s, true); +@@ -3060,7 +3264,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { + * sources if IN_IGNORED or IN_UNMOUNT is set. */ + LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { + +- if (s->enabled == SD_EVENT_OFF) ++ if (event_source_is_offline(s)) + continue; + + if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 && +@@ -3099,6 +3303,7 @@ static int process_inotify(sd_event *e) { + } + + static int source_dispatch(sd_event_source *s) { ++ _cleanup_(sd_event_unrefp) sd_event *saved_event = NULL; + EventSourceType saved_type; + int r = 0; + +@@ -3109,6 +3314,20 @@ static int source_dispatch(sd_event_source *s) { + * the event. */ + saved_type = s->type; + ++ /* Similar, store a reference to the event loop object, so that we can still access it after the ++ * callback might have invalidated/disconnected the event source. */ ++ saved_event = sd_event_ref(s->event); ++ ++ /* Check if we hit the ratelimit for this event source, if so, let's disable it. */ ++ assert(!s->ratelimited); ++ if (!ratelimit_below(&s->rate_limit)) { ++ r = event_source_enter_ratelimited(s); ++ if (r < 0) ++ return r; ++ ++ return 1; ++ } ++ + if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + r = source_set_pending(s, false); + if (r < 0) +@@ -3235,7 +3454,7 @@ static int event_prepare(sd_event *e) { + sd_event_source *s; + + s = prioq_peek(e->prepare); +- if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF) ++ if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s)) + break; + + s->prepare_iteration = e->iteration; +@@ -3269,7 +3488,7 @@ static int dispatch_exit(sd_event *e) { + assert(e); + + p = prioq_peek(e->exit); +- if (!p || p->enabled == SD_EVENT_OFF) { ++ if (!p || event_source_is_offline(p)) { + e->state = SD_EVENT_FINISHED; + return 0; + } +@@ -3291,7 +3510,7 @@ static sd_event_source* event_next_pending(sd_event *e) { + if (!p) + return NULL; + +- if (p->enabled == SD_EVENT_OFF) ++ if (event_source_is_offline(p)) + return NULL; + + return p; +@@ -3844,3 +4063,53 @@ _public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_d + + return !!s->destroy_callback; + } ++ ++_public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval, unsigned burst) { ++ int r; ++ ++ assert_return(s, -EINVAL); ++ ++ /* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing ++ * so is a programming error. */ ++ assert_return(EVENT_SOURCE_CAN_RATE_LIMIT(s->type), -EDOM); ++ ++ /* When ratelimiting is configured we'll always reset the rate limit state first and start fresh, ++ * non-ratelimited. */ ++ r = event_source_leave_ratelimit(s); ++ if (r < 0) ++ return r; ++ ++ RATELIMIT_INIT(s->rate_limit, interval, burst); ++ return 0; ++} ++ ++_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) { ++ assert_return(s, -EINVAL); ++ ++ /* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence ++ * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */ ++ if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) ++ return -EDOM; ++ ++ if (!ratelimit_configured(&s->rate_limit)) ++ return -ENOEXEC; ++ ++ if (ret_interval) ++ *ret_interval = s->rate_limit.interval; ++ if (ret_burst) ++ *ret_burst = s->rate_limit.burst; ++ ++ return 0; ++} ++ ++_public_ int sd_event_source_is_ratelimited(sd_event_source *s) { ++ assert_return(s, -EINVAL); ++ ++ if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) ++ return false; ++ ++ if (!ratelimit_configured(&s->rate_limit)) ++ return false; ++ ++ return s->ratelimited; ++} +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index 9876be01c6..a17a9b3488 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -144,6 +144,9 @@ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); + int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret); + int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback); + int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret); ++int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst); ++int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst); ++int sd_event_source_is_ratelimited(sd_event_source *s); + + /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ + _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); diff --git a/SOURCES/0560-test-add-ratelimiting-test.patch b/SOURCES/0560-test-add-ratelimiting-test.patch new file mode 100644 index 0000000..8e398e1 --- /dev/null +++ b/SOURCES/0560-test-add-ratelimiting-test.patch @@ -0,0 +1,127 @@ +From c35ba62cd6f337c4eef64cdc3b9796f988802229 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Mon, 23 Nov 2020 18:04:57 +0100 +Subject: [PATCH] test: add ratelimiting test + +(Taken from Michal's #17274 by Lennart, and slightly adjusted) + +(cherry picked from commit 68d890651781904a4c762ac866af36e30c4f7ff8) + +Related: #1819868 +--- + src/libsystemd/sd-event/test-event.c | 96 ++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c +index bde00cf719..e3ee4cd5c3 100644 +--- a/src/libsystemd/sd-event/test-event.c ++++ b/src/libsystemd/sd-event/test-event.c +@@ -482,6 +482,100 @@ static void test_inotify(unsigned n_create_events) { + sd_event_unref(e); + } + ++ ++static int ratelimit_io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { ++ unsigned *c = (unsigned*) userdata; ++ *c += 1; ++ return 0; ++} ++ ++static int ratelimit_time_handler(sd_event_source *s, uint64_t usec, void *userdata) { ++ int r; ++ ++ r = sd_event_source_set_enabled(s, SD_EVENT_ON); ++ if (r < 0) ++ log_warning_errno(r, "Failed to turn on notify event source: %m"); ++ ++ r = sd_event_source_set_time(s, usec + 1000); ++ if (r < 0) ++ log_error_errno(r, "Failed to restart watchdog event source: %m"); ++ ++ unsigned *c = (unsigned*) userdata; ++ *c += 1; ++ ++ return 0; ++} ++ ++static void test_ratelimit(void) { ++ _cleanup_close_pair_ int p[2] = {-1, -1}; ++ _cleanup_(sd_event_unrefp) sd_event *e = NULL; ++ _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; ++ uint64_t interval; ++ unsigned count, burst; ++ ++ assert_se(sd_event_default(&e) >= 0); ++ assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0); ++ ++ assert_se(sd_event_add_io(e, &s, p[0], EPOLLIN, ratelimit_io_handler, &count) >= 0); ++ assert_se(sd_event_source_set_description(s, "test-ratelimit-io") >= 0); ++ assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0); ++ assert_se(sd_event_source_get_ratelimit(s, &interval, &burst) >= 0); ++ assert_se(interval == 1 * USEC_PER_SEC && burst == 5); ++ ++ assert_se(write(p[1], "1", 1) == 1); ++ ++ count = 0; ++ for (unsigned i = 0; i < 10; i++) { ++ log_debug("slow loop iteration %u", i); ++ assert_se(sd_event_run(e, UINT64_MAX) >= 0); ++ assert_se(usleep(250 * USEC_PER_MSEC) >= 0); ++ } ++ ++ assert_se(sd_event_source_is_ratelimited(s) == 0); ++ assert_se(count == 10); ++ log_info("ratelimit_io_handler: called %d times, event source not ratelimited", count); ++ ++ assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0); ++ assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0); ++ ++ count = 0; ++ for (unsigned i = 0; i < 10; i++) { ++ log_debug("fast event loop iteration %u", i); ++ assert_se(sd_event_run(e, UINT64_MAX) >= 0); ++ assert_se(usleep(10) >= 0); ++ } ++ log_info("ratelimit_io_handler: called %d times, event source got ratelimited", count); ++ assert_se(count < 10); ++ ++ s = sd_event_source_unref(s); ++ safe_close_pair(p); ++ ++ count = 0; ++ ++ assert_se(sd_event_add_time(e, &s, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 1000, 0, ratelimit_time_handler, &count) >= 0); ++ assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) == 0); ++ ++ do { ++ assert_se(sd_event_run(e, UINT64_MAX) >= 0); ++ } while (!sd_event_source_is_ratelimited(s)); ++ ++ log_info("ratelimit_time_handler: called %d times, event source got ratelimited", count); ++ assert_se(count == 10); ++ ++ /* In order to get rid of active rate limit client needs to disable it explicitely */ ++ assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0); ++ assert_se(!sd_event_source_is_ratelimited(s)); ++ ++ assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) >= 0); ++ ++ do { ++ assert_se(sd_event_run(e, UINT64_MAX) >= 0); ++ } while (!sd_event_source_is_ratelimited(s)); ++ ++ log_info("ratelimit_time_handler: called 10 more times, event source got ratelimited"); ++ assert_se(count == 20); ++} ++ + int main(int argc, char *argv[]) { + + log_set_max_level(LOG_DEBUG); +@@ -494,5 +588,7 @@ int main(int argc, char *argv[]) { + test_inotify(100); /* should work without overflow */ + test_inotify(33000); /* should trigger a q overflow */ + ++ test_ratelimit(); ++ + return 0; + } diff --git a/SOURCES/0561-core-prevent-excessive-proc-self-mountinfo-parsing.patch b/SOURCES/0561-core-prevent-excessive-proc-self-mountinfo-parsing.patch new file mode 100644 index 0000000..71075e0 --- /dev/null +++ b/SOURCES/0561-core-prevent-excessive-proc-self-mountinfo-parsing.patch @@ -0,0 +1,29 @@ +From 51737206afaa10d902c86ec9b5ec97cf425039c2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Thu, 9 Jul 2020 18:16:44 +0200 +Subject: [PATCH] core: prevent excessive /proc/self/mountinfo parsing + +(cherry picked from commit d586f642fd90e3bb378f7b6d3e3a64a753e51756) + +Resolves: #1819868 +--- + src/core/mount.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 2746372db2..076dfd06a3 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1763,6 +1763,12 @@ static void mount_enumerate(Manager *m) { + goto fail; + } + ++ r = sd_event_source_set_ratelimit(m->mount_event_source, 1 * USEC_PER_SEC, 5); ++ if (r < 0) { ++ log_error_errno(r, "Failed to enable rate limit for mount events: %m"); ++ goto fail; ++ } ++ + (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch"); + } + diff --git a/SOURCES/0562-udev-run-link_update-with-increased-retry-count-in-s.patch b/SOURCES/0562-udev-run-link_update-with-increased-retry-count-in-s.patch new file mode 100644 index 0000000..90fb6ad --- /dev/null +++ b/SOURCES/0562-udev-run-link_update-with-increased-retry-count-in-s.patch @@ -0,0 +1,44 @@ +From 1f3165bda13c8572c8c31d23c998835c4e2ad8f3 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 4 Mar 2021 17:35:22 +0100 +Subject: [PATCH] udev: run link_update() with increased retry count in second + invocation + +In PR #17431 we have introduced retry loop in link_update() in order to +maximize the chance that we end up with correct target when there are +multiple contenders for given symlink. + +Number of iterations in retry loop is either 1 or +LINK_UPDATE_MAX_RETRIES, depending on the value of 'initialized' db +flag. When device appears for the first time we need to set the +flag before calling link_update() via update_devnode() for the second +time to make sure we run the second invocation with higher retry loop +counter. + +(cherry picked from commit 996c83903da5bf8b371314b4207ff97afeef65a4) + +Related: #1931947 +--- + src/udev/udev-event.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index 9004634f65..eaec05523b 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -934,14 +934,13 @@ void udev_event_execute_rules(struct udev_event *event, + /* (re)write database file */ + udev_device_tag_index(dev, event->dev_db, true); + udev_device_update_db(dev); ++ udev_device_set_is_initialized(dev); + + /* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database, + * it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure + * symlinks point to devices that claim them with the highest priority. */ + update_devnode(event); + +- udev_device_set_is_initialized(dev); +- + event->dev_db = udev_device_unref(event->dev_db); + } + } diff --git a/SOURCES/0563-pam-systemd-use-secure_getenv-rather-than-getenv.patch b/SOURCES/0563-pam-systemd-use-secure_getenv-rather-than-getenv.patch new file mode 100644 index 0000000..2eb7fc5 --- /dev/null +++ b/SOURCES/0563-pam-systemd-use-secure_getenv-rather-than-getenv.patch @@ -0,0 +1,89 @@ +From fcd9a141d08d521c01dc1a1c06a8d43a2337a392 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 4 Feb 2019 10:23:43 +0100 +Subject: [PATCH] pam-systemd: use secure_getenv() rather than getenv() + +And explain why in a comment. + +(cherry picked from commit 83d4ab55336ff8a0643c6aa627b31e351a24040a) + +CVE-2019-3842 + +Resolves: #1687514 +--- + src/login/pam_systemd.c | 55 ++++++++++++++++++++++++----------------- + 1 file changed, 32 insertions(+), 23 deletions(-) + +diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c +index 1fbf6ba585..78ddb7d398 100644 +--- a/src/login/pam_systemd.c ++++ b/src/login/pam_systemd.c +@@ -274,6 +274,33 @@ static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, con + return 0; + } + ++static const char* getenv_harder(pam_handle_t *handle, const char *key, const char *fallback) { ++ const char *v; ++ ++ assert(handle); ++ assert(key); ++ ++ /* Looks for an environment variable, preferrably in the environment block associated with the ++ * specified PAM handle, falling back to the process' block instead. Why check both? Because we want ++ * to permit configuration of session properties from unit files that invoke PAM services, so that ++ * PAM services don't have to be reworked to set systemd-specific properties, but these properties ++ * can still be set from the unit file Environment= block. */ ++ ++ v = pam_getenv(handle, key); ++ if (!isempty(v)) ++ return v; ++ ++ /* We use secure_getenv() here, since we might get loaded into su/sudo, which are SUID. Ideally ++ * they'd clean up the environment before invoking foreign code (such as PAM modules), but alas they ++ * currently don't (to be precise, they clean up the environment they pass to their children, but ++ * not their own environ[]). */ ++ v = secure_getenv(key); ++ if (!isempty(v)) ++ return v; ++ ++ return fallback; ++} ++ + _public_ PAM_EXTERN int pam_sm_open_session( + pam_handle_t *handle, + int flags, +@@ -352,29 +379,11 @@ _public_ PAM_EXTERN int pam_sm_open_session( + pam_get_item(handle, PAM_RUSER, (const void**) &remote_user); + pam_get_item(handle, PAM_RHOST, (const void**) &remote_host); + +- seat = pam_getenv(handle, "XDG_SEAT"); +- if (isempty(seat)) +- seat = getenv("XDG_SEAT"); +- +- cvtnr = pam_getenv(handle, "XDG_VTNR"); +- if (isempty(cvtnr)) +- cvtnr = getenv("XDG_VTNR"); +- +- type = pam_getenv(handle, "XDG_SESSION_TYPE"); +- if (isempty(type)) +- type = getenv("XDG_SESSION_TYPE"); +- if (isempty(type)) +- type = type_pam; +- +- class = pam_getenv(handle, "XDG_SESSION_CLASS"); +- if (isempty(class)) +- class = getenv("XDG_SESSION_CLASS"); +- if (isempty(class)) +- class = class_pam; +- +- desktop = pam_getenv(handle, "XDG_SESSION_DESKTOP"); +- if (isempty(desktop)) +- desktop = getenv("XDG_SESSION_DESKTOP"); ++ seat = getenv_harder(handle, "XDG_SEAT", NULL); ++ cvtnr = getenv_harder(handle, "XDG_VTNR", NULL); ++ type = getenv_harder(handle, "XDG_SESSION_TYPE", type_pam); ++ class = getenv_harder(handle, "XDG_SESSION_CLASS", class_pam); ++ desktop = getenv_harder(handle, "XDG_SESSION_DESKTOP", NULL); + + tty = strempty(tty); + diff --git a/SOURCES/0564-Revert-udev-run-link_update-with-increased-retry-cou.patch b/SOURCES/0564-Revert-udev-run-link_update-with-increased-retry-cou.patch new file mode 100644 index 0000000..a6ad6a9 --- /dev/null +++ b/SOURCES/0564-Revert-udev-run-link_update-with-increased-retry-cou.patch @@ -0,0 +1,33 @@ +From 1afb38f39a9b4508533cc1c7262e5fff418cb317 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 17 May 2021 15:49:08 +0200 +Subject: [PATCH] Revert "udev: run link_update() with increased retry count in + second invocation" + +This reverts commit 1f3165bda13c8572c8c31d23c998835c4e2ad8f3. + +Related: #1942299 +--- + src/udev/udev-event.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index eaec05523b..9004634f65 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -934,13 +934,14 @@ void udev_event_execute_rules(struct udev_event *event, + /* (re)write database file */ + udev_device_tag_index(dev, event->dev_db, true); + udev_device_update_db(dev); +- udev_device_set_is_initialized(dev); + + /* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database, + * it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure + * symlinks point to devices that claim them with the highest priority. */ + update_devnode(event); + ++ udev_device_set_is_initialized(dev); ++ + event->dev_db = udev_device_unref(event->dev_db); + } + } diff --git a/SOURCES/0565-Revert-udev-make-algorithm-that-selects-highest-prio.patch b/SOURCES/0565-Revert-udev-make-algorithm-that-selects-highest-prio.patch new file mode 100644 index 0000000..3d5cc9c --- /dev/null +++ b/SOURCES/0565-Revert-udev-make-algorithm-that-selects-highest-prio.patch @@ -0,0 +1,450 @@ +From 897b4d1e19c706d9198b9308125df57a5d469a6b Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 17 May 2021 15:50:31 +0200 +Subject: [PATCH] Revert "udev: make algorithm that selects highest priority + devlink less susceptible to race conditions" + +This reverts commit 1d5f966c1758eb620755fcae54abd07a1ac36d3d. + +Related: #1942299 +--- + src/udev/udev-event.c | 71 +++++------- + src/udev/udev-node.c | 244 ++++++++++++------------------------------ + 2 files changed, 99 insertions(+), 216 deletions(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index 9004634f65..fd8406d959 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -833,41 +833,6 @@ static int rename_netif(struct udev_event *event) { + return 0; + } + +-static void update_devnode(struct udev_event *event) { +- struct udev_device *dev = event->dev; +- +- if (major(udev_device_get_devnum(dev)) > 0) { +- bool apply; +- +- /* remove/update possible left-over symlinks from old database entry */ +- if (event->dev_db != NULL) +- udev_node_update_old_links(dev, event->dev_db); +- +- if (!event->owner_set) +- event->uid = udev_device_get_devnode_uid(dev); +- +- if (!event->group_set) +- event->gid = udev_device_get_devnode_gid(dev); +- +- if (!event->mode_set) { +- if (udev_device_get_devnode_mode(dev) > 0) { +- /* kernel supplied value */ +- event->mode = udev_device_get_devnode_mode(dev); +- } else if (event->gid > 0) { +- /* default 0660 if a group is assigned */ +- event->mode = 0660; +- } +- else { +- /* default 0600 */ +- event->mode = 0600; +- } +- } +- +- apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set; +- udev_node_add(dev, apply, event->mode, event->uid, event->gid, &event->seclabel_list); +- } +-} +- + void udev_event_execute_rules(struct udev_event *event, + usec_t timeout_usec, usec_t timeout_warn_usec, + struct udev_list *properties_list, +@@ -926,7 +891,35 @@ void udev_event_execute_rules(struct udev_event *event, + } + } + +- update_devnode(event); ++ if (major(udev_device_get_devnum(dev)) > 0) { ++ bool apply; ++ ++ /* remove/update possible left-over symlinks from old database entry */ ++ if (event->dev_db != NULL) ++ udev_node_update_old_links(dev, event->dev_db); ++ ++ if (!event->owner_set) ++ event->uid = udev_device_get_devnode_uid(dev); ++ ++ if (!event->group_set) ++ event->gid = udev_device_get_devnode_gid(dev); ++ ++ if (!event->mode_set) { ++ if (udev_device_get_devnode_mode(dev) > 0) { ++ /* kernel supplied value */ ++ event->mode = udev_device_get_devnode_mode(dev); ++ } else if (event->gid > 0) { ++ /* default 0660 if a group is assigned */ ++ event->mode = 0660; ++ } else { ++ /* default 0600 */ ++ event->mode = 0600; ++ } ++ } ++ ++ apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set; ++ udev_node_add(dev, apply, event->mode, event->uid, event->gid, &event->seclabel_list); ++ } + + /* preserve old, or get new initialization timestamp */ + udev_device_ensure_usec_initialized(event->dev, event->dev_db); +@@ -934,12 +927,6 @@ void udev_event_execute_rules(struct udev_event *event, + /* (re)write database file */ + udev_device_tag_index(dev, event->dev_db, true); + udev_device_update_db(dev); +- +- /* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database, +- * it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure +- * symlinks point to devices that claim them with the highest priority. */ +- update_devnode(event); +- + udev_device_set_is_initialized(dev); + + event->dev_db = udev_device_unref(event->dev_db); +diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c +index 2eeeccdd3a..333dcae6b9 100644 +--- a/src/udev/udev-node.c ++++ b/src/udev/udev-node.c +@@ -13,27 +13,19 @@ + #include + + #include "device-nodes.h" +-#include "device-private.h" + #include "dirent-util.h" +-#include "fd-util.h" + #include "format-util.h" + #include "fs-util.h" +-#include "sd-device.h" + #include "selinux-util.h" + #include "smack-util.h" +-#include "stat-util.h" + #include "stdio-util.h" + #include "string-util.h" + #include "udev.h" +-#include "libudev-device-internal.h" + +-#define LINK_UPDATE_MAX_RETRIES 128 +- +-static int node_symlink(sd_device *dev, const char *node, const char *slink) { ++static int node_symlink(struct udev_device *dev, const char *node, const char *slink) { + struct stat stats; + char target[UTIL_PATH_SIZE]; + char *s; +- const char *id_filename; + size_t l; + char slink_tmp[UTIL_PATH_SIZE + 32]; + int i = 0; +@@ -97,10 +89,7 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) { + } + + log_debug("atomically replace '%s'", slink); +- err = device_get_id_filename(dev, &id_filename); +- if (err < 0) +- return log_error_errno(err, "Failed to get id_filename: %m"); +- strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", id_filename, NULL); ++ strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), NULL); + unlink(slink_tmp); + do { + err = mkdir_parents_label(slink_tmp, 0755); +@@ -120,187 +109,104 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) { + if (err != 0) { + log_error_errno(errno, "rename '%s' '%s' failed: %m", slink_tmp, slink); + unlink(slink_tmp); +- } else +- /* Tell caller that we replaced already existing symlink. */ +- return 1; ++ } + exit: + return err; + } + + /* find device node of device with highest priority */ +-static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, char **ret) { +- _cleanup_closedir_ DIR *dir = NULL; +- _cleanup_free_ char *target = NULL; ++static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) { ++ struct udev *udev = udev_device_get_udev(dev); ++ DIR *dir; + struct dirent *dent; +- int r, priority = 0; +- +- assert(!add || dev); +- assert(stackdir); +- assert(ret); ++ int priority = 0; ++ const char *target = NULL; + + if (add) { +- const char *devnode; +- +- r = device_get_devlink_priority(dev, &priority); +- if (r < 0) +- return r; +- +- r = sd_device_get_devname(dev, &devnode); +- if (r < 0) +- return r; +- +- target = strdup(devnode); +- if (!target) +- return -ENOMEM; ++ priority = udev_device_get_devlink_priority(dev); ++ strscpy(buf, bufsize, udev_device_get_devnode(dev)); ++ target = buf; + } + + dir = opendir(stackdir); +- if (!dir) { +- if (target) { +- *ret = TAKE_PTR(target); +- return 0; +- } +- +- return -errno; +- } +- ++ if (dir == NULL) ++ return target; + FOREACH_DIRENT_ALL(dent, dir, break) { +- _cleanup_(sd_device_unrefp) sd_device *dev_db = NULL; +- const char *devnode, *id_filename; +- int db_prio = 0; ++ struct udev_device *dev_db; + + if (dent->d_name[0] == '\0') + break; + if (dent->d_name[0] == '.') + continue; + +- log_debug("Found '%s' claiming '%s'", dent->d_name, stackdir); +- +- if (device_get_id_filename(dev, &id_filename) < 0) +- continue; ++ log_debug("found '%s' claiming '%s'", dent->d_name, stackdir); + + /* did we find ourself? */ +- if (streq(dent->d_name, id_filename)) +- continue; +- +- if (sd_device_new_from_device_id(&dev_db, dent->d_name) < 0) ++ if (streq(dent->d_name, udev_device_get_id_filename(dev))) + continue; + +- if (sd_device_get_devname(dev_db, &devnode) < 0) +- continue; +- +- if (device_get_devlink_priority(dev_db, &db_prio) < 0) +- continue; +- +- if (target && db_prio <= priority) +- continue; +- +- if (DEBUG_LOGGING) { +- const char *syspath = NULL; +- +- (void) sd_device_get_syspath(dev_db, &syspath); +- log_debug("Device '%s' claims priority %i for '%s'", strnull(syspath), db_prio, stackdir); ++ dev_db = udev_device_new_from_device_id(udev, dent->d_name); ++ if (dev_db != NULL) { ++ const char *devnode; ++ ++ devnode = udev_device_get_devnode(dev_db); ++ if (devnode != NULL) { ++ if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) { ++ log_debug("'%s' claims priority %i for '%s'", ++ udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir); ++ priority = udev_device_get_devlink_priority(dev_db); ++ strscpy(buf, bufsize, devnode); ++ target = buf; ++ } ++ } ++ udev_device_unref(dev_db); + } +- +- r = free_and_strdup(&target, devnode); +- if (r < 0) +- return r; +- priority = db_prio; + } +- +- if (!target) +- return -ENOENT; +- +- *ret = TAKE_PTR(target); +- return 0; ++ closedir(dir); ++ return target; + } + +- + /* manage "stack of names" with possibly specified device priorities */ +-static int link_update(sd_device *dev, const char *slink, bool add) { +- _cleanup_free_ char *filename = NULL, *dirname = NULL; +- char name_enc[PATH_MAX]; +- const char *id_filename; +- int i, r, retries; +- +- assert(dev); +- assert(slink); +- +- r = device_get_id_filename(dev, &id_filename); +- if (r < 0) +- return log_debug_errno(r, "Failed to get id_filename: %m"); ++static void link_update(struct udev_device *dev, const char *slink, bool add) { ++ char name_enc[UTIL_PATH_SIZE]; ++ char filename[UTIL_PATH_SIZE * 2]; ++ char dirname[UTIL_PATH_SIZE]; ++ const char *target; ++ char buf[UTIL_PATH_SIZE]; + + util_path_encode(slink + STRLEN("/dev"), name_enc, sizeof(name_enc)); +- dirname = path_join(NULL, "/run/udev/links/", name_enc); +- if (!dirname) +- return log_oom(); +- filename = path_join(NULL, dirname, id_filename); +- if (!filename) +- return log_oom(); +- +- if (!add) { +- if (unlink(filename) == 0) +- (void) rmdir(dirname); +- } else +- for (;;) { +- _cleanup_close_ int fd = -1; +- +- r = mkdir_parents(filename, 0755); +- if (!IN_SET(r, 0, -ENOENT)) +- return r; +- +- fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); +- if (fd >= 0) +- break; +- if (errno != ENOENT) +- return -errno; +- } +- +- /* If the database entry is not written yet we will just do one iteration and possibly wrong symlink +- * will be fixed in the second invocation. */ +- (void) sd_device_get_is_initialized(dev, &r); +- retries = r > 0 ? LINK_UPDATE_MAX_RETRIES : 1; ++ strscpyl(dirname, sizeof(dirname), "/run/udev/links/", name_enc, NULL); ++ strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL); + +- for (i = 0; i < retries; i++) { +- _cleanup_free_ char *target = NULL; +- struct stat st1 = {}, st2 = {}; ++ if (!add && unlink(filename) == 0) ++ rmdir(dirname); + +- r = stat(dirname, &st1); +- if (r < 0 && errno != ENOENT) +- return -errno; +- +- r = link_find_prioritized(dev, add, dirname, &target); +- if (r == -ENOENT) { +- log_debug("No reference left, removing '%s'", slink); +- if (unlink(slink) == 0) +- (void) rmdir_parents(slink, "/"); +- +- break; +- } else if (r < 0) +- return log_error_errno(r, "Failed to determine highest priority symlink: %m"); ++ target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf)); ++ if (target == NULL) { ++ log_debug("no reference left, remove '%s'", slink); ++ if (unlink(slink) == 0) ++ rmdir_parents(slink, "/"); ++ } else { ++ log_debug("creating link '%s' to '%s'", slink, target); ++ node_symlink(dev, target, slink); ++ } + +- r = node_symlink(dev, target, slink); +- if (r < 0) { +- (void) unlink(filename); +- break; +- } else if (r == 1) +- /* We have replaced already existing symlink, possibly there is some other device trying +- * to claim the same symlink. Let's do one more iteration to give us a chance to fix +- * the error if other device actually claims the symlink with higher priority. */ +- continue; ++ if (add) { ++ int err; + +- /* Skip the second stat() if the first failed, stat_inode_unmodified() would return false regardless. */ +- if ((st1.st_mode & S_IFMT) != 0) { +- r = stat(dirname, &st2); +- if (r < 0 && errno != ENOENT) +- return -errno; ++ do { ++ int fd; + +- if (stat_inode_unmodified(&st1, &st2)) ++ err = mkdir_parents(filename, 0755); ++ if (!IN_SET(err, 0, -ENOENT)) + break; +- } ++ fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); ++ if (fd >= 0) ++ close(fd); ++ else ++ err = -errno; ++ } while (err == -ENOENT); + } +- +- return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP; + } + + void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) { +@@ -327,7 +233,7 @@ void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev + + log_debug("update old name, '%s' no longer belonging to '%s'", + name, udev_device_get_devpath(dev)); +- link_update(dev->device, name, false); ++ link_update(dev, name, false); + } + } + +@@ -432,16 +338,11 @@ void udev_node_add(struct udev_device *dev, bool apply, + xsprintf_dev_num_path(filename, + streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", + udev_device_get_devnum(dev)); +- node_symlink(dev->device, udev_device_get_devnode(dev), filename); ++ node_symlink(dev, udev_device_get_devnode(dev), filename); + + /* create/update symlinks, add symlinks to name index */ +- udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { +- int r; +- +- r = link_update(dev->device, udev_list_entry_get_name(list_entry), true); +- if (r < 0) +- log_info_errno(r, "Failed to update device symlinks: %m"); +- } ++ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) ++ link_update(dev, udev_list_entry_get_name(list_entry), true); + } + + void udev_node_remove(struct udev_device *dev) { +@@ -449,13 +350,8 @@ void udev_node_remove(struct udev_device *dev) { + char filename[DEV_NUM_PATH_MAX]; + + /* remove/update symlinks, remove symlinks from name index */ +- udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { +- int r; +- +- r = link_update(dev->device, udev_list_entry_get_name(list_entry), false); +- if (r < 0) +- log_info_errno(r, "Failed to update device symlinks: %m"); +- } ++ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) ++ link_update(dev, udev_list_entry_get_name(list_entry), false); + + /* remove /dev/{block,char}/$major:$minor */ + xsprintf_dev_num_path(filename, diff --git a/SOURCES/0566-test-udev-test.pl-drop-test-cases-that-add-mutliple-.patch b/SOURCES/0566-test-udev-test.pl-drop-test-cases-that-add-mutliple-.patch new file mode 100644 index 0000000..72eea13 --- /dev/null +++ b/SOURCES/0566-test-udev-test.pl-drop-test-cases-that-add-mutliple-.patch @@ -0,0 +1,204 @@ +From 94ad224240140a7287f9e2be5905b9c506350193 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 17 May 2021 15:54:10 +0200 +Subject: [PATCH] test/udev-test.pl: drop test cases that add mutliple devices + +[msekleta: It is easier to delete test-cases that would make +udev test fail. Once we reintroduce the fix for link_update() +we will revert this commit.] + +Related: #1942299 +--- + test/udev-test.pl | 179 ---------------------------------------------- + 1 file changed, 179 deletions(-) + +diff --git a/test/udev-test.pl b/test/udev-test.pl +index 0612859cda..343d9c01ae 100755 +--- a/test/udev-test.pl ++++ b/test/udev-test.pl +@@ -2041,185 +2041,6 @@ TAGS=="foo", SYMLINK+="found" + TAGS=="aaa", SYMLINK+="bad" + EOF + }, +- { +- desc => "multiple devices", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", +- exp_links => ["part-1"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", +- exp_links => ["part-5"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6", +- exp_links => ["part-6"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7", +- exp_links => ["part-7"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8", +- exp_links => ["part-8"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9", +- exp_links => ["part-9"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10", +- exp_links => ["part-10"], +- }, +- ], +- rules => < "multiple devices, same link name, positive prio", +- repeat => 100, +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", +- exp_links => ["part-1"], +- not_exp_links => ["partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", +- exp_links => ["part-5"], +- not_exp_links => ["partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6", +- not_exp_links => ["partition"], +- exp_links => ["part-6"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7", +- exp_links => ["part-7", "partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8", +- not_exp_links => ["partition"], +- exp_links => ["part-8"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9", +- not_exp_links => ["partition"], +- exp_links => ["part-9"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10", +- not_exp_links => ["partition"], +- exp_links => ["part-10"], +- }, +- ], +- rules => < "multiple devices, same link name, negative prio", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", +- exp_links => ["part-1"], +- not_exp_links => ["partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", +- exp_links => ["part-5"], +- not_exp_links => ["partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6", +- not_exp_links => ["partition"], +- exp_links => ["part-6"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7", +- exp_links => ["part-7", "partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8", +- not_exp_links => ["partition"], +- exp_links => ["part-8"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9", +- not_exp_links => ["partition"], +- exp_links => ["part-9"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10", +- not_exp_links => ["partition"], +- exp_links => ["part-10"], +- }, +- ], +- rules => < "multiple devices, same link name, positive prio, sleep", +- devices => [ +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", +- exp_links => ["part-1"], +- not_exp_links => ["partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", +- exp_links => ["part-5"], +- not_exp_links => ["partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6", +- not_exp_links => ["partition"], +- exp_links => ["part-6"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7", +- exp_links => ["part-7", "partition"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8", +- not_exp_links => ["partition"], +- exp_links => ["part-8"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9", +- not_exp_links => ["partition"], +- exp_links => ["part-9"], +- }, +- { +- devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10", +- not_exp_links => ["partition"], +- exp_links => ["part-10"], +- }, +- ], +- sleep_us => 10000, +- rules => < 'all_block_devs', +- generator => expect_for_some("\\/sda6\$", ["blockdev"]), +- repeat => 10, +- rules => < +Date: Sat, 17 Aug 2019 02:33:43 +0200 +Subject: [PATCH] cgroup: Also set io.bfq.weight + +Current kernels with BFQ scheduler do not yet set their IO weight +through "io.weight" but through "io.bfq.weight" (using a slightly +different interface supporting only default weights, not per-device +weights). This commit enables "IOWeight=" to just to that. + +This patch may be dropped at some time later. + +Github-Link: https://github.com/systemd/systemd/issues/7057 +Signed-off-by: Kai Krakow + +(cherry picked from commit 21221ce1ce9a572e82d46d80692afd65c224fc50) + +Related: #1927290 +--- + src/core/cgroup.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 71e30fd4db..f02cc31c6e 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -984,6 +984,14 @@ static void cgroup_context_apply( + log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set io.weight: %m"); + ++ /* FIXME: drop this when distro kernels properly support BFQ through "io.weight" ++ * See also: https://github.com/systemd/systemd/pull/13335 */ ++ xsprintf(buf, "%" PRIu64 "\n", weight); ++ r = cg_set_attribute("io", path, "io.bfq.weight", buf); ++ if (r < 0) ++ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, ++ "Failed to set io.bfq.weight: %m"); ++ + if (has_io) { + CGroupIODeviceWeight *w; + diff --git a/SOURCES/0568-seccomp-allow-turning-off-of-seccomp-filtering-via-e.patch b/SOURCES/0568-seccomp-allow-turning-off-of-seccomp-filtering-via-e.patch new file mode 100644 index 0000000..58d8b14 --- /dev/null +++ b/SOURCES/0568-seccomp-allow-turning-off-of-seccomp-filtering-via-e.patch @@ -0,0 +1,82 @@ +From e706f5df66b7189a7df526aeeb45c86b8c4b057a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Nov 2020 14:51:10 +0100 +Subject: [PATCH] seccomp: allow turning off of seccomp filtering via env var + +Fixes: #17504 + +(While we are it, also move $SYSTEMD_SECCOMP_LOG= env var description +into the right document section) + +Also suggested in: https://github.com/systemd/systemd/issues/17245#issuecomment-704773603 + +(cherry picked from commit ce8f6d478e3f6c6a313fb19615aa5029bb18f86d) + +Resolves: #1916835 +--- + doc/ENVIRONMENT.md | 3 +++ + src/nspawn/nspawn-seccomp.c | 2 +- + src/shared/seccomp-util.c | 19 +++++++++++++++---- + 3 files changed, 19 insertions(+), 5 deletions(-) + +diff --git a/doc/ENVIRONMENT.md b/doc/ENVIRONMENT.md +index 0e763b6302..36b649afe1 100644 +--- a/doc/ENVIRONMENT.md ++++ b/doc/ENVIRONMENT.md +@@ -117,3 +117,6 @@ systemd-sulogin-shell: + * `$SYSTEMD_SULOGIN_FORCE=1` — This skips asking for the root password if the + root password is not available (such as when the root account is locked). + See `sulogin(8)` for more details. ++ ++* `$SYSTEMD_SECCOMP=0` – if set, seccomp filters will not be enforced, even if ++ support for it is compiled in and available in the kernel. +diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c +index b56c5b04a8..fba22644da 100644 +--- a/src/nspawn/nspawn-seccomp.c ++++ b/src/nspawn/nspawn-seccomp.c +@@ -172,7 +172,7 @@ int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **sys + int r; + + if (!is_seccomp_available()) { +- log_debug("SECCOMP features not detected in the kernel, disabling SECCOMP filterering"); ++ log_debug("SECCOMP features not detected in the kernel or disabled at runtime, disabling SECCOMP filtering"); + return 0; + } + +diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c +index d91fb4e269..e903512d45 100644 +--- a/src/shared/seccomp-util.c ++++ b/src/shared/seccomp-util.c +@@ -12,6 +12,7 @@ + + #include "af-list.h" + #include "alloc-util.h" ++#include "env-util.h" + #include "macro.h" + #include "nsflags.h" + #include "process-util.h" +@@ -244,10 +245,20 @@ static bool is_seccomp_filter_available(void) { + bool is_seccomp_available(void) { + static int cached_enabled = -1; + +- if (cached_enabled < 0) +- cached_enabled = +- is_basic_seccomp_available() && +- is_seccomp_filter_available(); ++ if (cached_enabled < 0) { ++ int b; ++ ++ b = getenv_bool("SYSTEMD_SECCOMP"); ++ if (b != 0) { ++ if (b < 0 && b != -ENXIO) /* ENXIO: env var unset */ ++ log_debug_errno(b, "Failed to parse $SYSTEMD_SECCOMP value, ignoring."); ++ ++ cached_enabled = ++ is_basic_seccomp_available() && ++ is_seccomp_filter_available(); ++ } else ++ cached_enabled = false; ++ } + + return cached_enabled; + } diff --git a/SOURCES/0569-meson-remove-strange-dep-that-causes-meson-to-enter-.patch b/SOURCES/0569-meson-remove-strange-dep-that-causes-meson-to-enter-.patch new file mode 100644 index 0000000..9029c4b --- /dev/null +++ b/SOURCES/0569-meson-remove-strange-dep-that-causes-meson-to-enter-.patch @@ -0,0 +1,36 @@ +From 7fb2d86b58201341a582b739a5445821bec66eea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 6 Nov 2019 12:44:39 +0100 +Subject: [PATCH] meson: remove strange dep that causes meson to enter infinite + loop + +The value is obviously bogus, but didn't seem to cause problems so far. +With meson-0.52.0, it causes a hang. The number of aliases is always rather +small (usually just one or two, possibly up to a dozen in a few cases), so +even if this causes some looping, it is strange that it has such a huge impact. +But let's just remove it. + +Fixes #13742. + +Tested with meson-0.52.0-1.module_f31+6771+f5d842eb.noarch, +meson-0.51.1-1.fc29.noarch. + +(cherry picked from commit af336643a01d0b210b18312c253a50594ba54b0a) + +Resolves: #1970860 +--- + man/meson.build | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/man/meson.build b/man/meson.build +index ec05d73bc6..a953d34098 100644 +--- a/man/meson.build ++++ b/man/meson.build +@@ -68,7 +68,6 @@ foreach tuple : xsltproc.found() ? manpages : [] + foreach htmlalias : htmlaliases + link = custom_target( + htmlalias, +- input : p2, + output : htmlalias, + command : ['ln', '-fs', html, '@OUTPUT@']) + if want_html diff --git a/SOURCES/0570-copy-handle-copy_file_range-weirdness-on-procfs-sysf.patch b/SOURCES/0570-copy-handle-copy_file_range-weirdness-on-procfs-sysf.patch new file mode 100644 index 0000000..b14a3c7 --- /dev/null +++ b/SOURCES/0570-copy-handle-copy_file_range-weirdness-on-procfs-sysf.patch @@ -0,0 +1,182 @@ +From 8df650c7c5adc2bb24a0077d8332f5ee342e7fd8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 26 Feb 2021 10:25:24 +0100 +Subject: [PATCH] copy: handle copy_file_range() weirdness on procfs/sysfs + +This addresses the issue described in https://lwn.net/Articles/846403/ +and makes sure we will be able to stream bytes from procfs/sysfs via +copy_bytes() if people ask us to. + +Based on: ee1aa61c4710ae567a2b844e0f0bb8cb0456ab8c +Related: #1970860 +--- + src/basic/copy.c | 75 +++++++++++++++++++++++++++++--------------- + src/test/test-copy.c | 17 ++++++++++ + 2 files changed, 66 insertions(+), 26 deletions(-) + +diff --git a/src/basic/copy.c b/src/basic/copy.c +index e06a503a29..a48c42c5c6 100644 +--- a/src/basic/copy.c ++++ b/src/basic/copy.c +@@ -92,7 +92,7 @@ int copy_bytes_full( + void **ret_remains, + size_t *ret_remains_size) { + +- bool try_cfr = true, try_sendfile = true, try_splice = true; ++ bool try_cfr = true, try_sendfile = true, try_splice = true, copied_something = false; + int r, nonblock_pipe = -1; + size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */ + +@@ -185,9 +185,20 @@ int copy_bytes_full( + + try_cfr = false; + /* use fallback below */ +- } else if (n == 0) /* EOF */ +- break; +- else ++ } else if (n == 0) { /* likely EOF */ ++ ++ if (copied_something) ++ break; ++ ++ /* So, we hit EOF immediately, without having copied a single byte. This ++ * could indicate two things: the file is actually empty, or we are on some ++ * virtual file system such as procfs/sysfs where the syscall actually ++ * doesn't work but doesn't return an error. Try to handle that, by falling ++ * back to simple read()s in case we encounter empty files. ++ * ++ * See: https://lwn.net/Articles/846403/ */ ++ try_cfr = try_sendfile = try_splice = false; ++ } else + /* Success! */ + goto next; + } +@@ -201,9 +212,14 @@ int copy_bytes_full( + + try_sendfile = false; + /* use fallback below */ +- } else if (n == 0) /* EOF */ ++ } else if (n == 0) { /* likely EOF */ ++ ++ if (copied_something) ++ break; ++ ++ try_sendfile = try_splice = false; /* same logic as above for copy_file_range() */ + break; +- else ++ } else + /* Success! */ + goto next; + } +@@ -213,14 +229,14 @@ int copy_bytes_full( + + /* splice()'s asynchronous I/O support is a bit weird. When it encounters a pipe file + * descriptor, then it will ignore its O_NONBLOCK flag and instead only honour the +- * SPLICE_F_NONBLOCK flag specified in its flag parameter. Let's hide this behaviour here, and +- * check if either of the specified fds are a pipe, and if so, let's pass the flag +- * automatically, depending on O_NONBLOCK being set. ++ * SPLICE_F_NONBLOCK flag specified in its flag parameter. Let's hide this behaviour ++ * here, and check if either of the specified fds are a pipe, and if so, let's pass ++ * the flag automatically, depending on O_NONBLOCK being set. + * +- * Here's a twist though: when we use it to move data between two pipes of which one has +- * O_NONBLOCK set and the other has not, then we have no individual control over O_NONBLOCK +- * behaviour. Hence in that case we can't use splice() and still guarantee systematic +- * O_NONBLOCK behaviour, hence don't. */ ++ * Here's a twist though: when we use it to move data between two pipes of which one ++ * has O_NONBLOCK set and the other has not, then we have no individual control over ++ * O_NONBLOCK behaviour. Hence in that case we can't use splice() and still guarantee ++ * systematic O_NONBLOCK behaviour, hence don't. */ + + if (nonblock_pipe < 0) { + int a, b; +@@ -238,12 +254,13 @@ int copy_bytes_full( + (a == FD_IS_BLOCKING_PIPE && b == FD_IS_NONBLOCKING_PIPE) || + (a == FD_IS_NONBLOCKING_PIPE && b == FD_IS_BLOCKING_PIPE)) + +- /* splice() only works if one of the fds is a pipe. If neither is, let's skip +- * this step right-away. As mentioned above, if one of the two fds refers to a +- * blocking pipe and the other to a non-blocking pipe, we can't use splice() +- * either, hence don't try either. This hence means we can only use splice() if +- * either only one of the two fds is a pipe, or if both are pipes with the same +- * nonblocking flag setting. */ ++ /* splice() only works if one of the fds is a pipe. If neither is, ++ * let's skip this step right-away. As mentioned above, if one of the ++ * two fds refers to a blocking pipe and the other to a non-blocking ++ * pipe, we can't use splice() either, hence don't try either. This ++ * hence means we can only use splice() if either only one of the two ++ * fds is a pipe, or if both are pipes with the same nonblocking flag ++ * setting. */ + + try_splice = false; + else +@@ -259,9 +276,13 @@ int copy_bytes_full( + + try_splice = false; + /* use fallback below */ +- } else if (n == 0) /* EOF */ +- break; +- else ++ } else if (n == 0) { /* likely EOF */ ++ ++ if (copied_something) ++ break; ++ ++ try_splice = false; /* same logic as above for copy_file_range() + sendfile() */ ++ } else + /* Success! */ + goto next; + } +@@ -312,11 +333,13 @@ int copy_bytes_full( + assert(max_bytes >= (uint64_t) n); + max_bytes -= n; + } +- /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, +- * so reduce our maximum by the amount we already copied, +- * but don't go below our copy buffer size, unless we are +- * close the limit of bytes we are allowed to copy. */ ++ ++ /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, so reduce our maximum by the ++ * amount we already copied, but don't go below our copy buffer size, unless we are close the ++ * limit of bytes we are allowed to copy. */ + m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); ++ ++ copied_something = true; + } + + return 0; /* return 0 if we hit EOF earlier than the size limit */ +diff --git a/src/test/test-copy.c b/src/test/test-copy.c +index 2e8d251ac1..29ac33e47a 100644 +--- a/src/test/test-copy.c ++++ b/src/test/test-copy.c +@@ -253,6 +253,22 @@ static void test_copy_atomic(void) { + assert_se(copy_file_atomic("/etc/fstab", q, 0644, 0, COPY_REPLACE) >= 0); + } + ++static void test_copy_proc(void) { ++ _cleanup_(rm_rf_physical_and_freep) char *p = NULL; ++ _cleanup_free_ char *f = NULL, *a = NULL, *b = NULL; ++ ++ /* Check if copying data from /proc/ works correctly, i.e. let's see if https://lwn.net/Articles/846403/ is a problem for us */ ++ ++ assert_se(mkdtemp_malloc(NULL, &p) >= 0); ++ assert_se(f = path_join(NULL, p, "version")); ++ assert_se(copy_file("/proc/version", f, 0, (mode_t) -1, 0, 0) >= 0); ++ ++ assert_se(read_one_line_file("/proc/version", &a) >= 0); ++ assert_se(read_one_line_file(f, &b) >= 0); ++ assert_se(streq(a, b)); ++ assert_se(strlen(a) > 0); ++} ++ + int main(int argc, char *argv[]) { + log_set_max_level(LOG_DEBUG); + +@@ -267,6 +283,7 @@ int main(int argc, char *argv[]) { + test_copy_bytes_regular_file(argv[0], false, 32000); /* larger than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 32000); + test_copy_atomic(); ++ test_copy_proc(); + + return 0; + } diff --git a/SOURCES/0571-core-Hide-Deactivated-successfully-message.patch b/SOURCES/0571-core-Hide-Deactivated-successfully-message.patch new file mode 100644 index 0000000..1ec2d8a --- /dev/null +++ b/SOURCES/0571-core-Hide-Deactivated-successfully-message.patch @@ -0,0 +1,33 @@ +From 4dc498258bd0cce1bc8ad2311c5f12de5678e0af Mon Sep 17 00:00:00 2001 +From: Jan Macku +Date: Thu, 27 May 2021 12:25:51 +0200 +Subject: [PATCH] core: Hide "Deactivated successfully" message + +Show message "Deactivated successfully" in debug mode (when manager is +user) rather than in info mode. This message has low information value +for regular users and it might be a bit overwhelming on a system with +a lot of devices. + +(cherry picked from commit edf2ee22f54005d76b2fb8fdcc9c60974feb88bc) + +Resolves: #1954802 +--- + src/core/unit.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index cd3e7c806d..93c13e58d9 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -5525,7 +5525,10 @@ int unit_pid_attachable(Unit *u, pid_t pid, sd_bus_error *error) { + void unit_log_success(Unit *u) { + assert(u); + +- log_struct(LOG_INFO, ++ /* Let's show message "Deactivated successfully" in debug mode (when manager is user) rather than in info mode. ++ * This message has low information value for regular users and it might be a bit overwhelming on a system with ++ * a lot of devices. */ ++ log_struct(MANAGER_IS_USER(u->manager) ? LOG_DEBUG : LOG_INFO, + "MESSAGE_ID=" SD_MESSAGE_UNIT_SUCCESS_STR, + LOG_UNIT_ID(u), + LOG_UNIT_INVOCATION_ID(u), diff --git a/SOURCES/0572-util-rework-in_initrd-to-make-use-of-path_is_tempora.patch b/SOURCES/0572-util-rework-in_initrd-to-make-use-of-path_is_tempora.patch new file mode 100644 index 0000000..bdc3418 --- /dev/null +++ b/SOURCES/0572-util-rework-in_initrd-to-make-use-of-path_is_tempora.patch @@ -0,0 +1,35 @@ +From 42f639d3689b7cbc9ce6b9578a2790c254508384 Mon Sep 17 00:00:00 2001 +From: Kairui Song +Date: Fri, 8 Jan 2021 14:52:26 +0800 +Subject: [PATCH] util: rework in_initrd() to make use of + path_is_temporary_fs() + +(cherry picked from commit 96cceb35e7985f5ee6c9b17e129a76259273cdde) + +Related: #1959339 +--- + src/basic/util.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/basic/util.c b/src/basic/util.c +index 82cb937314..b443e639f3 100644 +--- a/src/basic/util.c ++++ b/src/basic/util.c +@@ -130,7 +130,6 @@ int prot_from_flags(int flags) { + } + + bool in_initrd(void) { +- struct statfs s; + + if (saved_in_initrd >= 0) + return saved_in_initrd; +@@ -146,8 +145,7 @@ bool in_initrd(void) { + */ + + saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && +- statfs("/", &s) >= 0 && +- is_temporary_fs(&s); ++ path_is_temporary_fs("/") > 0; + + return saved_in_initrd; + } diff --git a/SOURCES/0573-initrd-extend-SYSTEMD_IN_INITRD-to-accept-non-ramfs-.patch b/SOURCES/0573-initrd-extend-SYSTEMD_IN_INITRD-to-accept-non-ramfs-.patch new file mode 100644 index 0000000..0b3202f --- /dev/null +++ b/SOURCES/0573-initrd-extend-SYSTEMD_IN_INITRD-to-accept-non-ramfs-.patch @@ -0,0 +1,99 @@ +From 99ca5b681fceedd010b2616b1248a483f4bfbd97 Mon Sep 17 00:00:00 2001 +From: Kairui Song +Date: Wed, 13 Jan 2021 00:04:53 +0800 +Subject: [PATCH] initrd: extend SYSTEMD_IN_INITRD to accept non-ramfs rootfs + +Sometimes, non-ramfs initrd root are useful. Eg, for kdump, because +initramfs is memory consuming, so mount a compressed image in earlier +initrd, chroot into it then let systemd do the rest of job is a good +solution. + +But systemd doesn't recognize the initrd environment if rootfs is not a +temporary fs. This is a reasonable check, because switch-root in initrd +will wipe the whole rootfs, will be a disaster if there are any +misdetect. + +So extend SYSTEMD_IN_INITRD environment variable, now it accepts boolean +value and two extra keyword, "auto" and "lenient". "auto" is same as +before, and it's the default value. "lenient" will let systemd bypass +the rootfs check. + +(cherry picked from commit db4c45cf4f10ca094b9e9570b758abd445d65381) + +Related: #1959339 +--- + doc/ENVIRONMENT.md | 8 ++++++++ + src/basic/util.c | 28 +++++++++++++++++++++++++--- + 2 files changed, 33 insertions(+), 3 deletions(-) + +diff --git a/doc/ENVIRONMENT.md b/doc/ENVIRONMENT.md +index 36b649afe1..8d7ce6ae2c 100644 +--- a/doc/ENVIRONMENT.md ++++ b/doc/ENVIRONMENT.md +@@ -37,6 +37,14 @@ All tools: + useful for debugging, in order to test generators and other code against + specific kernel command lines. + ++* `$SYSTEMD_IN_INITRD=[auto|lenient|0|1]` — if set, specifies initrd detection ++ method. Defaults to `auto`. Behavior is defined as follows: ++ `auto`: Checks if `/etc/initrd-release` exists, and a temporary fs is mounted ++ on `/`. If both conditions meet, then it's in initrd. ++ `lenient`: Similiar to `auto`, but the rootfs check is skipped. ++ `0|1`: Simply overrides initrd detection. This is useful for debugging and ++ testing initrd-only programs in the main system. ++ + * `$SYSTEMD_EMOJI=0` — if set, tools such as "systemd-analyze security" will + not output graphical smiley emojis, but ASCII alternatives instead. Note that + this only controls use of Unicode emoji glyphs, and has no effect on other +diff --git a/src/basic/util.c b/src/basic/util.c +index b443e639f3..59bcf7b00c 100644 +--- a/src/basic/util.c ++++ b/src/basic/util.c +@@ -130,11 +130,14 @@ int prot_from_flags(int flags) { + } + + bool in_initrd(void) { ++ int r; ++ const char *e; ++ bool lenient = false; + + if (saved_in_initrd >= 0) + return saved_in_initrd; + +- /* We make two checks here: ++ /* We have two checks here: + * + * 1. the flag file /etc/initrd-release must exist + * 2. the root file system must be a memory file system +@@ -142,10 +145,29 @@ bool in_initrd(void) { + * The second check is extra paranoia, since misdetecting an + * initrd can have bad consequences due the initrd + * emptying when transititioning to the main systemd. ++ * ++ * If env var $SYSTEMD_IN_INITRD is not set or set to "auto", ++ * both checks are used. If it's set to "lenient", only check ++ * 1 is used. If set to a booleen value, then the boolean ++ * value is returned. + */ + +- saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && +- path_is_temporary_fs("/") > 0; ++ e = secure_getenv("SYSTEMD_IN_INITRD"); ++ if (e) { ++ if (streq(e, "lenient")) ++ lenient = true; ++ else if (!streq(e, "auto")) { ++ r = parse_boolean(e); ++ if (r >= 0) { ++ saved_in_initrd = r > 0; ++ return saved_in_initrd; ++ } ++ log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m"); ++ } ++ } ++ ++ saved_in_initrd = (lenient || path_is_temporary_fs("/") > 0) && ++ access("/etc/initrd-release", F_OK) >= 0; + + return saved_in_initrd; + } diff --git a/SOURCES/0574-initrd-do-a-debug-log-if-failed-to-detect-rootfs-typ.patch b/SOURCES/0574-initrd-do-a-debug-log-if-failed-to-detect-rootfs-typ.patch new file mode 100644 index 0000000..cda944e --- /dev/null +++ b/SOURCES/0574-initrd-do-a-debug-log-if-failed-to-detect-rootfs-typ.patch @@ -0,0 +1,35 @@ +From 3299c855c6e65596ff9d8635dcbd45ff6818499a Mon Sep 17 00:00:00 2001 +From: Kairui Song +Date: Thu, 14 Jan 2021 00:39:10 +0800 +Subject: [PATCH] initrd: do a debug log if failed to detect rootfs type + +(cherry picked from commit 3377c740d9121f38385e70d6a380b5e4bd8c672a) + +Related: #1959339 +--- + src/basic/util.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/basic/util.c b/src/basic/util.c +index 59bcf7b00c..fef52ad5ff 100644 +--- a/src/basic/util.c ++++ b/src/basic/util.c +@@ -166,8 +166,16 @@ bool in_initrd(void) { + } + } + +- saved_in_initrd = (lenient || path_is_temporary_fs("/") > 0) && +- access("/etc/initrd-release", F_OK) >= 0; ++ if (!lenient) { ++ r = path_is_temporary_fs("/"); ++ if (r < 0) ++ log_debug_errno(r, "Couldn't determine if / is a temporary file system: %m"); ++ ++ saved_in_initrd = r > 0; ++ } ++ ++ if (saved_in_initrd != 0) ++ saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0; + + return saved_in_initrd; + } diff --git a/SOURCES/0575-initrd-do-a-debug-log-if-etc-initrd-release-doesn-t-.patch b/SOURCES/0575-initrd-do-a-debug-log-if-etc-initrd-release-doesn-t-.patch new file mode 100644 index 0000000..f31ba4c --- /dev/null +++ b/SOURCES/0575-initrd-do-a-debug-log-if-etc-initrd-release-doesn-t-.patch @@ -0,0 +1,39 @@ +From a1417c121d19272b1389098648132106a5ffc661 Mon Sep 17 00:00:00 2001 +From: Kairui Song +Date: Thu, 14 Jan 2021 01:25:20 +0800 +Subject: [PATCH] initrd: do a debug log if /etc/initrd-release doesn't take + effect + +Signed-off-by: Kairui Song + +(cherry picked from commit 4a60d8cbcae574896a28f9f1f6204a1bddca8e99) + +Related: #1959339 +--- + src/basic/util.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/basic/util.c b/src/basic/util.c +index fef52ad5ff..609f8c2f33 100644 +--- a/src/basic/util.c ++++ b/src/basic/util.c +@@ -174,8 +174,17 @@ bool in_initrd(void) { + saved_in_initrd = r > 0; + } + +- if (saved_in_initrd != 0) +- saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0; ++ r = access("/etc/initrd-release", F_OK); ++ if (r >= 0) { ++ if (saved_in_initrd == 0) ++ log_debug("/etc/initrd-release exists, but it's not an initrd."); ++ else ++ saved_in_initrd = 1; ++ } else { ++ if (errno != ENOENT) ++ log_debug_errno(errno, "Failed to test if /etc/initrd-release exists: %m"); ++ saved_in_initrd = 0; ++ } + + return saved_in_initrd; + } diff --git a/SOURCES/0576-units-assign-user-runtime-dir-.service-to-user-i.sli.patch b/SOURCES/0576-units-assign-user-runtime-dir-.service-to-user-i.sli.patch new file mode 100644 index 0000000..ea2c0ce --- /dev/null +++ b/SOURCES/0576-units-assign-user-runtime-dir-.service-to-user-i.sli.patch @@ -0,0 +1,25 @@ +From 64975b046d5a0877690aa6de9389b8234ee1cfab Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Aug 2018 10:45:31 +0200 +Subject: [PATCH] units: assign user-runtime-dir@.service to user-%i.slice + +This service won't use much resources, but it's certainly nicer to see +it attached th the user's slice along with user@.service, so that +everything we run for a specific user is properly bound into one unit. + +(cherry picked from commit 1193c11a04b3ecc29925904fbeb5d64834bce73e) + +Related: #1946453 +--- + units/user-runtime-dir@.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/user-runtime-dir@.service.in b/units/user-runtime-dir@.service.in +index 8c02beda3b..13b3ed52f8 100644 +--- a/units/user-runtime-dir@.service.in ++++ b/units/user-runtime-dir@.service.in +@@ -15,3 +15,4 @@ StopWhenUnneeded=yes + ExecStart=@rootlibexecdir@/systemd-user-runtime-dir start %i + ExecStop=@rootlibexecdir@/systemd-user-runtime-dir stop %i + RemainAfterExit=true ++Slice=user-%i.slice diff --git a/SOURCES/0577-units-order-user-runtime-dir-.service-after-systemd-.patch b/SOURCES/0577-units-order-user-runtime-dir-.service-after-systemd-.patch new file mode 100644 index 0000000..c852f8d --- /dev/null +++ b/SOURCES/0577-units-order-user-runtime-dir-.service-after-systemd-.patch @@ -0,0 +1,30 @@ +From 1fa9a6bf51a1a1d0fa2ccc23283739d16e9179b4 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Aug 2018 10:42:09 +0200 +Subject: [PATCH] units: order user-runtime-dir@.service after + systemd-user-sessions.service + +We use systemd-user-sessions.service as barrier when to allow login +sessions. With this patch user@.service is ordered after that too, so +that any login related code (which user-runtime-dir@.service is) is +guaranteed to run after the barrier, and never before. + +(cherry picked from commit eb748aef4fbfd03b64938aa471bb8ceda1bc89a8) + +Related: #1946453 +--- + units/user-runtime-dir@.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/user-runtime-dir@.service.in b/units/user-runtime-dir@.service.in +index 13b3ed52f8..31354c9bf2 100644 +--- a/units/user-runtime-dir@.service.in ++++ b/units/user-runtime-dir@.service.in +@@ -9,6 +9,7 @@ + + [Unit] + Description=/run/user/%i mount wrapper ++After=systemd-user-sessions.service + StopWhenUnneeded=yes + + [Service] diff --git a/SOURCES/0578-units-make-sure-user-runtime-dir-.service-is-Type-on.patch b/SOURCES/0578-units-make-sure-user-runtime-dir-.service-is-Type-on.patch new file mode 100644 index 0000000..493f4c6 --- /dev/null +++ b/SOURCES/0578-units-make-sure-user-runtime-dir-.service-is-Type-on.patch @@ -0,0 +1,26 @@ +From 780d1d9fa7ccc036e6e237221ac51ed69453c8c6 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Aug 2018 20:57:56 +0200 +Subject: [PATCH] units: make sure user-runtime-dir@.service is Type=oneshot + +We order user@.service after it, hence we need to properly know when it +finished starting up. + +(cherry picked from commit d06e8fbce35c2b52ee1d09af4888876d5f2d7ae4) + +Related: #1946453 +--- + units/user-runtime-dir@.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/user-runtime-dir@.service.in b/units/user-runtime-dir@.service.in +index 31354c9bf2..bfd6488d61 100644 +--- a/units/user-runtime-dir@.service.in ++++ b/units/user-runtime-dir@.service.in +@@ -15,5 +15,6 @@ StopWhenUnneeded=yes + [Service] + ExecStart=@rootlibexecdir@/systemd-user-runtime-dir start %i + ExecStop=@rootlibexecdir@/systemd-user-runtime-dir stop %i ++Type=oneshot + RemainAfterExit=true + Slice=user-%i.slice diff --git a/SOURCES/0579-user-runtime-dir-downgrade-a-few-log-messages-to-LOG.patch b/SOURCES/0579-user-runtime-dir-downgrade-a-few-log-messages-to-LOG.patch new file mode 100644 index 0000000..1a577ba --- /dev/null +++ b/SOURCES/0579-user-runtime-dir-downgrade-a-few-log-messages-to-LOG.patch @@ -0,0 +1,52 @@ +From 354b894aa3e79f54ab75bf6fae76ce28ca80db38 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 2 Aug 2018 20:56:34 +0200 +Subject: [PATCH] user-runtime-dir: downgrade a few log messages to LOG_DEBUG + that we ignore + +As the comments already say it might be quite likely that +$XDG_RUNTIME_DIR is not set up as mount, and we shouldn't complain about +that. + +Moreover, let's make this idempotent, so that a runtime dir that is +already gone and is removed again doesn't cause failure. + +(cherry picked from commit 3a13442bbf72e7ebdd0b4d60c2922ea7c5cc9496) + +Related: #1946453 +--- + src/login/user-runtime-dir.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c +index 1bb26c99e4..9693821990 100644 +--- a/src/login/user-runtime-dir.c ++++ b/src/login/user-runtime-dir.c +@@ -95,20 +95,19 @@ static int user_remove_runtime_path(const char *runtime_path) { + + r = rm_rf(runtime_path, 0); + if (r < 0) +- log_error_errno(r, "Failed to remove runtime directory %s (before unmounting): %m", runtime_path); ++ log_debug_errno(r, "Failed to remove runtime directory %s (before unmounting), ignoring: %m", runtime_path); + +- /* Ignore cases where the directory isn't mounted, as that's +- * quite possible, if we lacked the permissions to mount +- * something */ ++ /* Ignore cases where the directory isn't mounted, as that's quite possible, if we lacked the permissions to ++ * mount something */ + r = umount2(runtime_path, MNT_DETACH); + if (r < 0 && !IN_SET(errno, EINVAL, ENOENT)) +- log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", runtime_path); ++ log_debug_errno(errno, "Failed to unmount user runtime directory %s, ignoring: %m", runtime_path); + + r = rm_rf(runtime_path, REMOVE_ROOT); +- if (r < 0) +- log_error_errno(r, "Failed to remove runtime directory %s (after unmounting): %m", runtime_path); ++ if (r < 0 && r != -ENOENT) ++ return log_error_errno(r, "Failed to remove runtime directory %s (after unmounting): %m", runtime_path); + +- return r; ++ return 0; + } + + static int do_mount(const char *runtime_path, uid_t uid, gid_t gid) { diff --git a/SOURCES/0580-shared-install-Preserve-escape-characters-for-escape.patch b/SOURCES/0580-shared-install-Preserve-escape-characters-for-escape.patch new file mode 100644 index 0000000..beb7ac3 --- /dev/null +++ b/SOURCES/0580-shared-install-Preserve-escape-characters-for-escape.patch @@ -0,0 +1,33 @@ +From 91ed691ff73d4d71fae8f6896a1bba73e6a76bba Mon Sep 17 00:00:00 2001 +From: David Michael +Date: Wed, 20 Mar 2019 15:14:32 +0000 +Subject: [PATCH] shared/install: Preserve escape characters for escaped unit + names + +Since switching to extract_first_word with no flags for parsing +unit names in 4c9565eea534cd233a913c8c21f7920dba229743, escape +characters will be stripped from escaped unit names such as +"mnt-persistent\x2dvolume.mount" resulting in the unit not being +configured as defined. Preserve escape characters again for +compatibility with existing preset definitions. + +(cherry picked from commit 82bd4da71e9cdd5a2e9266332f5a7399845e31f6) + +Resolves: #1952686 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index c2847df3f8..c9fef6bde2 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2774,7 +2774,7 @@ static int split_pattern_into_name_and_instances(const char *pattern, char **out + assert(out_instances); + assert(out_unit_name); + +- r = extract_first_word(&pattern, &unit_name, NULL, 0); ++ r = extract_first_word(&pattern, &unit_name, NULL, EXTRACT_RETAIN_ESCAPE); + if (r < 0) + return r; + diff --git a/SOURCES/0581-basic-virt-Detect-PowerVM-hypervisor.patch b/SOURCES/0581-basic-virt-Detect-PowerVM-hypervisor.patch new file mode 100644 index 0000000..38da2c0 --- /dev/null +++ b/SOURCES/0581-basic-virt-Detect-PowerVM-hypervisor.patch @@ -0,0 +1,80 @@ +From 48dacf8d30cd61b72939e9c3419acced4b2fde74 Mon Sep 17 00:00:00 2001 +From: Michal Suchanek +Date: Fri, 2 Oct 2020 11:05:23 +0200 +Subject: [PATCH] basic/virt: Detect PowerVM hypervisor + +Currently systemd-detect-virt fails to detect running under PowerVM. + +Add code to detect PowerVM based on code in util-linux. + +Signed-off-by: Michal Suchanek +(cherry picked from commit 3224e38bb6b3287ca253cbafb460a150544d5818) + +Resolves: #1937989 +--- + man/systemd-detect-virt.xml | 7 ++++++- + src/basic/virt.c | 6 ++++++ + src/basic/virt.h | 1 + + 3 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml +index c4763fd561..6beb2c2aa1 100644 +--- a/man/systemd-detect-virt.xml ++++ b/man/systemd-detect-virt.xml +@@ -65,7 +65,7 @@ + + + +- VM ++ VM + qemu + QEMU software virtualization, without KVM + +@@ -95,6 +95,11 @@ + Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems), for legacy and KVM hypervisor + + ++ ++ powervm ++ IBM PowerVM hypervisor - comes as firmware with some IBM POWER servers ++ ++ + + xen + Xen hypervisor (only domU, not dom0) +diff --git a/src/basic/virt.c b/src/basic/virt.c +index dfa1525219..0b88005ed6 100644 +--- a/src/basic/virt.c ++++ b/src/basic/virt.c +@@ -92,6 +92,11 @@ static int detect_vm_device_tree(void) { + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *dent; + ++ if (access("/proc/device-tree/ibm,partition-name", F_OK) == 0 && ++ access("/proc/device-tree/hmc-managed?", F_OK) == 0 && ++ access("/proc/device-tree/chosen/qemu,graphic-width", F_OK) != 0) ++ return VIRTUALIZATION_POWERVM; ++ + dir = opendir("/proc/device-tree"); + if (!dir) { + if (errno == ENOENT) { +@@ -635,6 +640,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { + [VIRTUALIZATION_PARALLELS] = "parallels", + [VIRTUALIZATION_BHYVE] = "bhyve", + [VIRTUALIZATION_QNX] = "qnx", ++ [VIRTUALIZATION_POWERVM] = "powervm", + [VIRTUALIZATION_VM_OTHER] = "vm-other", + + [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn", +diff --git a/src/basic/virt.h b/src/basic/virt.h +index c4cf4bfeab..640b3ed779 100644 +--- a/src/basic/virt.h ++++ b/src/basic/virt.h +@@ -21,6 +21,7 @@ enum { + VIRTUALIZATION_PARALLELS, + VIRTUALIZATION_BHYVE, + VIRTUALIZATION_QNX, ++ VIRTUALIZATION_POWERVM, + VIRTUALIZATION_VM_OTHER, + VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER, + diff --git a/SOURCES/0582-man-document-differences-in-clean-exit-status-for-Ty.patch b/SOURCES/0582-man-document-differences-in-clean-exit-status-for-Ty.patch new file mode 100644 index 0000000..233523a --- /dev/null +++ b/SOURCES/0582-man-document-differences-in-clean-exit-status-for-Ty.patch @@ -0,0 +1,57 @@ +From 102f4ff97a24c2ddaf6e569c678a0a713f972863 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Fri, 19 Mar 2021 10:05:47 +0100 +Subject: [PATCH] man: document differences in clean exit status for + Type=oneshot + +See commit 1f0958f640b87175cd547c1e69084cfe54a22e9d . + +(cherry picked from commit f055cf77862bc580f3afbfaac161d1c060f39411) + +Resolves: #1940078 +--- + man/systemd.service.xml | 24 +++++++++++++++--------- + 1 file changed, 15 insertions(+), 9 deletions(-) + +diff --git a/man/systemd.service.xml b/man/systemd.service.xml +index 54586d1948..1e30a564df 100644 +--- a/man/systemd.service.xml ++++ b/man/systemd.service.xml +@@ -669,14 +669,19 @@ + If set to (the default), the service will + not be restarted. If set to , it + will be restarted only when the service process exits cleanly. +- In this context, a clean exit means an exit code of 0, or one +- of the signals +- SIGHUP, +- SIGINT, +- SIGTERM or +- SIGPIPE, and +- additionally, exit statuses and signals specified in +- SuccessExitStatus=. If set to ++ In this context, a clean exit means any of the following: ++ ++ exit code of 0; ++ for types other than ++ Type=oneshot, one of the signals ++ SIGHUP, ++ SIGINT, ++ SIGTERM, or ++ SIGPIPE; ++ exit statuses and signals specified in ++ SuccessExitStatus=. ++ ++ If set to + , the service will be restarted + when the process exits with a non-zero exit code, is + terminated by a signal (including on core dump, but excluding +@@ -798,7 +803,8 @@ + Takes a list of exit status definitions that, + when returned by the main service process, will be considered + successful termination, in addition to the normal successful +- exit code 0 and the signals SIGHUP, ++ exit code 0 and, except for Type=oneshot, ++ the signals SIGHUP, + SIGINT, SIGTERM, and + SIGPIPE. Exit status definitions can + either be numeric exit codes or termination signal names, diff --git a/SOURCES/0583-busctl-add-a-timestamp-to-the-output-of-the-busctl-m.patch b/SOURCES/0583-busctl-add-a-timestamp-to-the-output-of-the-busctl-m.patch new file mode 100644 index 0000000..c40d0fd --- /dev/null +++ b/SOURCES/0583-busctl-add-a-timestamp-to-the-output-of-the-busctl-m.patch @@ -0,0 +1,42 @@ +From 53673326ea78039b27e1dbd5328a8fe9a1a17445 Mon Sep 17 00:00:00 2001 +From: d032747 +Date: Tue, 15 Dec 2020 10:40:06 +0100 +Subject: [PATCH] busctl: add a timestamp to the output of the busctl monitor + command + +(cherry picked from commit 6fe2a70b9160e35fdeed9d37bd31727c2d46a8b2) + +Resolves: #1909214 +--- + src/libsystemd/sd-bus/bus-dump.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c +index 2bd06053a6..36f592e0ba 100644 +--- a/src/libsystemd/sd-bus/bus-dump.c ++++ b/src/libsystemd/sd-bus/bus-dump.c +@@ -55,6 +55,15 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { + f = stdout; + + if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) { ++ char buf[FORMAT_TIMESTAMP_MAX]; ++ const char *p; ++ usec_t ts = m->realtime; ++ ++ if (ts == 0) ++ ts = now(CLOCK_REALTIME); ++ ++ p = format_timestamp_us_utc(buf, sizeof(buf), ts); ++ + fprintf(f, + "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64, + m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() : +@@ -82,6 +91,8 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) { + if (m->reply_cookie != 0) + fprintf(f, " ReplyCookie=%" PRIu64, m->reply_cookie); + ++ fprintf(f, " Timestamp=\"%s\"", strna(p)); ++ + fputs("\n", f); + + if (m->sender) diff --git a/SOURCES/0584-basic-cap-list-parse-print-numerical-capabilities.patch b/SOURCES/0584-basic-cap-list-parse-print-numerical-capabilities.patch new file mode 100644 index 0000000..2a0c9a6 --- /dev/null +++ b/SOURCES/0584-basic-cap-list-parse-print-numerical-capabilities.patch @@ -0,0 +1,90 @@ +From 240c55f1526300daac640ef2c1f4941de4579493 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 9 Jul 2020 23:15:47 +0200 +Subject: [PATCH] basic/cap-list: parse/print numerical capabilities + +We would refuse to print capabilities which were didn't have a name +for. The kernel adds new capabilities from time to time, most recently +cap_bpf. 'systmectl show -p CapabilityBoundingSet ...' would fail with +"Failed to parse bus message: Invalid argument" because +capability_set_to_string_alloc() would fail with -EINVAL. So let's +print such capabilities in hexadecimal: + +CapabilityBoundingSet=cap_chown cap_dac_override cap_dac_read_search + cap_fowner cap_fsetid cap_kill cap_setgid cap_setuid cap_setpcap + cap_linux_immutable cap_net_bind_service cap_net_broadcast cap_net_admin + cap_net_raw cap_ipc_lock cap_ipc_owner 0x10 0x11 0x12 0x13 0x14 0x15 0x16 + 0x17 0x18 0x19 0x1a ... + +For symmetry, also allow capabilities that we don't know to be specified. + +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1853736. + +(cherry picked from commit 417770f3033c426ca848b158d0bf057cd8ad1329) + +Resolves: #1946943 +--- + src/basic/cap-list.c | 10 +++++++--- + src/test/test-cap-list.c | 4 +++- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c +index bfcda33520..56a81c7dfc 100644 +--- a/src/basic/cap-list.c ++++ b/src/basic/cap-list.c +@@ -10,6 +10,7 @@ + #include "macro.h" + #include "missing.h" + #include "parse-util.h" ++#include "stdio-util.h" + #include "util.h" + + static const struct capability_name* lookup_capability(register const char *str, register GPERF_LEN_TYPE len); +@@ -37,7 +38,7 @@ int capability_from_name(const char *name) { + /* Try to parse numeric capability */ + r = safe_atoi(name, &i); + if (r >= 0) { +- if (i >= 0 && i < (int) ELEMENTSOF(capability_names)) ++ if (i >= 0 && i < 64) + return i; + else + return -EINVAL; +@@ -65,11 +66,14 @@ int capability_set_to_string_alloc(uint64_t set, char **s) { + for (i = 0; i < cap_last_cap(); i++) + if (set & (UINT64_C(1) << i)) { + const char *p; ++ char buf[2 + 16 + 1]; + size_t add; + + p = capability_to_name(i); +- if (!p) +- return -EINVAL; ++ if (!p) { ++ xsprintf(buf, "0x%lx", i); ++ p = buf; ++ } + + add = strlen(p); + +diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c +index de5fa729cc..84bbb7b7e7 100644 +--- a/src/test/test-cap-list.c ++++ b/src/test/test-cap-list.c +@@ -30,6 +30,8 @@ static void test_cap_list(void) { + assert_se(capability_from_name("cAp_aUdIt_rEAd") == CAP_AUDIT_READ); + assert_se(capability_from_name("0") == 0); + assert_se(capability_from_name("15") == 15); ++ assert_se(capability_from_name("63") == 63); ++ assert_se(capability_from_name("64") == -EINVAL); + assert_se(capability_from_name("-1") == -EINVAL); + + for (i = 0; i < capability_list_length(); i++) { +@@ -64,7 +66,7 @@ static void test_capability_set_one(uint64_t c, const char *t) { + + free(t1); + assert_se(t1 = strjoin("'cap_chown cap_dac_override' \"cap_setgid cap_setuid\"", t, +- " hogehoge foobar 12345 3.14 -3 ", t)); ++ " hogehoge foobar 18446744073709551616 3.14 -3 ", t)); + assert_se(capability_set_from_string(t1, &c1) == 0); + assert_se(c1 == c_masked); + } diff --git a/SOURCES/0585-shared-mount-util-convert-to-libmount.patch b/SOURCES/0585-shared-mount-util-convert-to-libmount.patch new file mode 100644 index 0000000..0c3a221 --- /dev/null +++ b/SOURCES/0585-shared-mount-util-convert-to-libmount.patch @@ -0,0 +1,318 @@ +From ca634baa10e2249d4a706d59b67be764867e5f32 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 30 Nov 2020 10:37:06 +0100 +Subject: [PATCH] shared/mount-util: convert to libmount + +It seems better to use just a single parsing algorithm for /proc/self/mountinfo. + +Also, unify the naming of variables in all places that use mnt_table_next_fs(). +It makes it easier to compare the different call sites. + +(cherry picked from commit 13dcfe4661b467131c943620d0f44711798bfd54) + +Related: #1885143 +--- + src/basic/mount-util.c | 133 ++++++++++++++++++----------------------- + src/core/mount.c | 22 +++---- + src/core/umount.c | 14 ++--- + 3 files changed, 76 insertions(+), 93 deletions(-) + +diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c +index 5b04e21f34..bac1a25cc8 100644 +--- a/src/basic/mount-util.c ++++ b/src/basic/mount-util.c +@@ -13,7 +13,6 @@ + #include + + #include "alloc-util.h" +-#include "escape.h" + #include "extract-word.h" + #include "fd-util.h" + #include "fileio.h" +@@ -27,6 +26,9 @@ + #include "string-util.h" + #include "strv.h" + ++DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table); ++DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter); ++ + /* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of + * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code + * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with +@@ -313,55 +315,43 @@ int umount_recursive(const char *prefix, int flags) { + * unmounting them until they are gone. */ + + do { +- _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; ++ _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL; ++ _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL; + + again = false; +- r = 0; + +- proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); +- if (!proc_self_mountinfo) +- return -errno; ++ table = mnt_new_table(); ++ iter = mnt_new_iter(MNT_ITER_FORWARD); ++ if (!table || !iter) ++ return -ENOMEM; + +- (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER); ++ r = mnt_table_parse_mtab(table, NULL); ++ if (r < 0) ++ return log_debug_errno(r, "Failed to parse /proc/self/mountinfo: %m"); + + for (;;) { +- _cleanup_free_ char *path = NULL, *p = NULL; +- int k; +- +- k = fscanf(proc_self_mountinfo, +- "%*s " /* (1) mount id */ +- "%*s " /* (2) parent id */ +- "%*s " /* (3) major:minor */ +- "%*s " /* (4) root */ +- "%ms " /* (5) mount point */ +- "%*s" /* (6) mount options */ +- "%*[^-]" /* (7) optional fields */ +- "- " /* (8) separator */ +- "%*s " /* (9) file system type */ +- "%*s" /* (10) mount source */ +- "%*s" /* (11) mount options 2 */ +- "%*[^\n]", /* some rubbish at the end */ +- &path); +- if (k != 1) { +- if (k == EOF) +- break; ++ struct libmnt_fs *fs; ++ const char *path; + +- continue; +- } +- +- r = cunescape(path, UNESCAPE_RELAX, &p); ++ r = mnt_table_next_fs(table, iter, &fs); ++ if (r == 1) ++ break; + if (r < 0) +- return r; ++ return log_debug_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m"); + +- if (!path_startswith(p, prefix)) ++ path = mnt_fs_get_target(fs); ++ if (!path) + continue; + +- if (umount2(p, flags) < 0) { +- r = log_debug_errno(errno, "Failed to umount %s: %m", p); ++ if (!path_startswith(path, prefix)) ++ continue; ++ ++ if (umount2(path, flags) < 0) { ++ r = log_debug_errno(errno, "Failed to umount %s: %m", path); + continue; + } + +- log_debug("Successfully unmounted %s", p); ++ log_debug("Successfully unmounted %s", path); + + again = true; + n++; +@@ -416,6 +406,8 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl + + for (;;) { + _cleanup_set_free_free_ Set *todo = NULL; ++ _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL; ++ _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL; + bool top_autofs = false; + char *x; + unsigned long orig_flags; +@@ -424,58 +416,52 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl + if (!todo) + return -ENOMEM; + ++ table = mnt_new_table(); ++ iter = mnt_new_iter(MNT_ITER_FORWARD); ++ if (!table || !iter) ++ return -ENOMEM; ++ + rewind(proc_self_mountinfo); + +- for (;;) { +- _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL; +- int k; +- +- k = fscanf(proc_self_mountinfo, +- "%*s " /* (1) mount id */ +- "%*s " /* (2) parent id */ +- "%*s " /* (3) major:minor */ +- "%*s " /* (4) root */ +- "%ms " /* (5) mount point */ +- "%*s" /* (6) mount options (superblock) */ +- "%*[^-]" /* (7) optional fields */ +- "- " /* (8) separator */ +- "%ms " /* (9) file system type */ +- "%*s" /* (10) mount source */ +- "%*s" /* (11) mount options (bind mount) */ +- "%*[^\n]", /* some rubbish at the end */ +- &path, +- &type); +- if (k != 2) { +- if (k == EOF) +- break; ++ r = mnt_table_parse_stream(table, proc_self_mountinfo, "/proc/self/mountinfo"); ++ if (r < 0) ++ return log_debug_errno(r, "Failed to parse /proc/self/mountinfo: %m"); + +- continue; +- } ++ for (;;) { ++ struct libmnt_fs *fs; ++ const char *path, *type; + +- r = cunescape(path, UNESCAPE_RELAX, &p); ++ r = mnt_table_next_fs(table, iter, &fs); ++ if (r == 1) ++ break; + if (r < 0) +- return r; ++ return log_debug_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m"); ++ ++ path = mnt_fs_get_target(fs); ++ type = mnt_fs_get_fstype(fs); ++ if (!path || !type) ++ continue; + +- if (!path_startswith(p, cleaned)) ++ if (!path_startswith(path, cleaned)) + continue; + +- /* Ignore this mount if it is blacklisted, but only if it isn't the top-level mount we shall +- * operate on. */ +- if (!path_equal(cleaned, p)) { ++ /* Ignore this mount if it is blacklisted, but only if it isn't the top-level mount ++ * we shall operate on. */ ++ if (!path_equal(path, cleaned)) { + bool blacklisted = false; + char **i; + + STRV_FOREACH(i, blacklist) { +- + if (path_equal(*i, cleaned)) + continue; + + if (!path_startswith(*i, cleaned)) + continue; + +- if (path_startswith(p, *i)) { ++ if (path_startswith(path, *i)) { + blacklisted = true; +- log_debug("Not remounting %s, because blacklisted by %s, called for %s", p, *i, cleaned); ++ log_debug("Not remounting %s blacklisted by %s, called for %s", ++ path, *i, cleaned); + break; + } + } +@@ -490,15 +476,12 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl + * already triggered, then we will find + * another entry for this. */ + if (streq(type, "autofs")) { +- top_autofs = top_autofs || path_equal(cleaned, p); ++ top_autofs = top_autofs || path_equal(path, cleaned); + continue; + } + +- if (!set_contains(done, p)) { +- r = set_consume(todo, p); +- p = NULL; +- if (r == -EEXIST) +- continue; ++ if (!set_contains(done, path)) { ++ r = set_put_strdup(todo, path); + if (r < 0) + return r; + } +diff --git a/src/core/mount.c b/src/core/mount.c +index 076dfd06a3..7e80a0c974 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1606,18 +1606,18 @@ fail: + } + + static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { +- _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL; +- _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL; +- int r = 0; ++ _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL; ++ _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL; ++ int r; + + assert(m); + +- t = mnt_new_table(); +- i = mnt_new_iter(MNT_ITER_FORWARD); +- if (!t || !i) ++ table = mnt_new_table(); ++ iter = mnt_new_iter(MNT_ITER_FORWARD); ++ if (!table || !iter) + return log_oom(); + +- r = mnt_table_parse_mtab(t, NULL); ++ r = mnt_table_parse_mtab(table, NULL); + if (r < 0) + return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m"); + +@@ -1628,11 +1628,11 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { + _cleanup_free_ char *d = NULL, *p = NULL; + int k; + +- k = mnt_table_next_fs(t, i, &fs); +- if (k == 1) ++ r = mnt_table_next_fs(table, iter, &fs); ++ if (r == 1) + break; +- if (k < 0) +- return log_error_errno(k, "Failed to get next entry from /proc/self/mountinfo: %m"); ++ if (r < 0) ++ return log_error_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m"); + + device = mnt_fs_get_source(fs); + path = mnt_fs_get_target(fs); +diff --git a/src/core/umount.c b/src/core/umount.c +index 241fe6fc62..3f02bf141a 100644 +--- a/src/core/umount.c ++++ b/src/core/umount.c +@@ -55,18 +55,18 @@ void mount_points_list_free(MountPoint **head) { + } + + int mount_points_list_get(const char *mountinfo, MountPoint **head) { +- _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL; +- _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL; ++ _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL; ++ _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL; + int r; + + assert(head); + +- t = mnt_new_table(); +- i = mnt_new_iter(MNT_ITER_FORWARD); +- if (!t || !i) ++ table = mnt_new_table(); ++ iter = mnt_new_iter(MNT_ITER_FORWARD); ++ if (!table || !iter) + return log_oom(); + +- r = mnt_table_parse_mtab(t, mountinfo); ++ r = mnt_table_parse_mtab(table, mountinfo); + if (r < 0) + return log_error_errno(r, "Failed to parse %s: %m", mountinfo); + +@@ -79,7 +79,7 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) { + bool try_remount_ro; + MountPoint *m; + +- r = mnt_table_next_fs(t, i, &fs); ++ r = mnt_table_next_fs(table, iter, &fs); + if (r == 1) + break; + if (r < 0) diff --git a/SOURCES/0586-mount-util-bind_remount-avoid-calling-statvfs.patch b/SOURCES/0586-mount-util-bind_remount-avoid-calling-statvfs.patch new file mode 100644 index 0000000..a212238 --- /dev/null +++ b/SOURCES/0586-mount-util-bind_remount-avoid-calling-statvfs.patch @@ -0,0 +1,92 @@ +From 996f88461c45e8620c5a8a0c958dc133bd02c50e Mon Sep 17 00:00:00 2001 +From: Jakob Unterwurzacher +Date: Mon, 30 Nov 2020 10:27:48 +0100 +Subject: [PATCH] mount-util: bind_remount: avoid calling statvfs + +The commit +"util: Do not clear parent mount flags when setting up namespaces" +introduced a statvfs call read the flags of the original mount +and have them applied to the bind mount. + +This has two problems: + +(1) The mount flags returned by statvfs(2) do not match the flags +accepted by mount(2). For example, the value 4096 means ST_RELATIME +when returned by statvfs(2), but means MS_BIND when passed to mount(2). + +(2) A call to statvfs blocks indefinitely when ran against a disconnected +network drive ( https://github.com/systemd/systemd/issues/12667 ). + +We already use libmount to parse `/proc/self/mountinfo` but did not use the +mount flag information from there. This patch changes that to use the mount +flags parsed by libmount instead of calling statvfs. Only if getting the +flags through libmount fails we call statvfs. + +Fixes https://github.com/systemd/systemd/issues/12667 + +(cherry picked from commit d34a40082db3ffca8de66bfa4df50951101bdae5) + +Resolves: #1885143 +--- + src/basic/mount-util.c | 31 +++++++++++++++++++++++++++---- + 1 file changed, 27 insertions(+), 4 deletions(-) + +diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c +index bac1a25cc8..2cf98eaa84 100644 +--- a/src/basic/mount-util.c ++++ b/src/basic/mount-util.c +@@ -364,11 +364,34 @@ int umount_recursive(const char *prefix, int flags) { + return r ? r : n; + } + +-static int get_mount_flags(const char *path, unsigned long *flags) { +- struct statvfs buf; ++/* Get the mount flags for the mountpoint at "path" from "table" */ ++static int get_mount_flags(const char *path, unsigned long *flags, struct libmnt_table *table) { ++ struct statvfs buf = {}; ++ struct libmnt_fs *fs = NULL; ++ const char *opts = NULL; ++ int r = 0; ++ ++ fs = mnt_table_find_target(table, path, MNT_ITER_FORWARD); ++ if (fs == NULL) { ++ log_warning("Could not find '%s' in mount table", path); ++ goto fallback; ++ } ++ ++ opts = mnt_fs_get_vfs_options(fs); ++ r = mnt_optstr_get_flags(opts, flags, mnt_get_builtin_optmap(MNT_LINUX_MAP)); ++ if (r != 0) { ++ log_warning_errno(r, "Could not get flags for '%s': %m", path); ++ goto fallback; ++ } + ++ /* relatime is default and trying to set it in an unprivileged container causes EPERM */ ++ *flags &= ~MS_RELATIME; ++ return 0; ++ ++fallback: + if (statvfs(path, &buf) < 0) + return -errno; ++ + *flags = buf.f_flag; + return 0; + } +@@ -501,7 +524,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl + return -errno; + + orig_flags = 0; +- (void) get_mount_flags(cleaned, &orig_flags); ++ (void) get_mount_flags(cleaned, &orig_flags, table); + orig_flags &= ~MS_RDONLY; + + if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) +@@ -535,7 +558,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl + + /* Try to reuse the original flag set */ + orig_flags = 0; +- (void) get_mount_flags(x, &orig_flags); ++ (void) get_mount_flags(x, &orig_flags, table); + orig_flags &= ~MS_RDONLY; + + if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) diff --git a/SOURCES/0587-mount-util-use-UMOUNT_NOFOLLOW-in-recursive-umounter.patch b/SOURCES/0587-mount-util-use-UMOUNT_NOFOLLOW-in-recursive-umounter.patch new file mode 100644 index 0000000..80fadef --- /dev/null +++ b/SOURCES/0587-mount-util-use-UMOUNT_NOFOLLOW-in-recursive-umounter.patch @@ -0,0 +1,30 @@ +From b6ffe7ec63d86c5ac66171d6731068b87e3e7b50 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Sat, 27 Jun 2020 11:13:01 +0200 +Subject: [PATCH] mount-util: use UMOUNT_NOFOLLOW in recursive umounter + +When we only want to unmount mount points below some path then it is +against our interest to follow symlinks. Hence don't. + +(cherry picked from commit 827ea5212507c3833b6ae14cdf65e446b36b5e05) + +Related: #1885143 +--- + src/basic/mount-util.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c +index 2cf98eaa84..be26bb5ec1 100644 +--- a/src/basic/mount-util.c ++++ b/src/basic/mount-util.c +@@ -346,8 +346,8 @@ int umount_recursive(const char *prefix, int flags) { + if (!path_startswith(path, prefix)) + continue; + +- if (umount2(path, flags) < 0) { +- r = log_debug_errno(errno, "Failed to umount %s: %m", path); ++ if (umount2(path, flags | UMOUNT_NOFOLLOW) < 0) { ++ log_debug_errno(errno, "Failed to umount %s: %m", path); + continue; + } + diff --git a/SOURCES/0588-test-install-root-create-referenced-targets.patch b/SOURCES/0588-test-install-root-create-referenced-targets.patch new file mode 100644 index 0000000..7ac367e --- /dev/null +++ b/SOURCES/0588-test-install-root-create-referenced-targets.patch @@ -0,0 +1,29 @@ +From 55cde82204724df756a198da691471f2f3f83d5a Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Wed, 31 Mar 2021 10:08:31 +0200 +Subject: [PATCH] test-install-root: create referenced targets + +(cherry picked from commit cd228002ccedb927b4531a4b7dd9ea7015fdb657) + +Related: #1835351 +--- + src/test/test-install-root.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +index fe1ca5b16f..f8b41b04db 100644 +--- a/src/test/test-install-root.c ++++ b/src/test/test-install-root.c +@@ -1061,6 +1061,12 @@ int main(int argc, char *argv[]) { + p = strjoina(root, "/usr/lib/systemd/system-preset/"); + assert_se(mkdir_p(p, 0755) >= 0); + ++ p = strjoina(root, "/usr/lib/systemd/system/multi-user.target"); ++ assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/graphical.target"); ++ assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); ++ + test_basic_mask_and_enable(root); + test_linked_units(root); + test_default(root); diff --git a/SOURCES/0589-install-warn-if-WantedBy-targets-don-t-exist.patch b/SOURCES/0589-install-warn-if-WantedBy-targets-don-t-exist.patch new file mode 100644 index 0000000..88f445c --- /dev/null +++ b/SOURCES/0589-install-warn-if-WantedBy-targets-don-t-exist.patch @@ -0,0 +1,113 @@ +From dfb4e03e0865d189a5c171072d6d7b31f49e1088 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 3 Jun 2020 10:33:21 +0200 +Subject: [PATCH] install: warn if WantedBy targets don't exist + +Currently, if [Install] section contains WantedBy=target that doesn't exist, +systemd creates the symlinks anyway. That is just user-unfriendly. +Let's be nice and warn about installing non-existent targets. + +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1835351. + +Replaces: #15834 +(cherry picked from commit 8ae27441c2dcf585f58242991302b09778d4d710) + +Resolves: #1835351 +--- + src/shared/install.c | 25 ++++++++++++++++++------- + src/shared/install.h | 1 + + 2 files changed, 19 insertions(+), 7 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index c9fef6bde2..055b09f98c 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -362,6 +362,11 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang + log_info("Unit %s is an alias to a unit that is not present, ignoring.", + changes[i].path); + break; ++ case UNIT_FILE_DESTINATION_NOT_PRESENT: ++ if (!quiet) ++ log_warning("Unit %s is added as a dependency to a non-existent unit %s.", ++ changes[i].source, changes[i].path); ++ break; + case -EEXIST: + if (changes[i].source) + log_error_errno(changes[i].type, +@@ -1730,6 +1735,7 @@ static int install_info_symlink_alias( + } + + static int install_info_symlink_wants( ++ UnitFileScope scope, + UnitFileInstallInfo *i, + const LookupPaths *paths, + const char *config_path, +@@ -1795,6 +1801,9 @@ static int install_info_symlink_wants( + q = create_symlink(paths, i->path, path, true, changes, n_changes); + if (r == 0) + r = q; ++ ++ if (unit_file_exists(scope, paths, dst) == 0) ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_DESTINATION_NOT_PRESENT, dst, i->path); + } + + return r; +@@ -1830,6 +1839,7 @@ static int install_info_symlink_link( + } + + static int install_info_apply( ++ UnitFileScope scope, + UnitFileInstallInfo *i, + const LookupPaths *paths, + const char *config_path, +@@ -1848,11 +1858,11 @@ static int install_info_apply( + + r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes); + +- q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes); ++ q = install_info_symlink_wants(scope, i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes); + if (r == 0) + r = q; + +- q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes); ++ q = install_info_symlink_wants(scope, i, paths, config_path, i->required_by, ".requires/", changes, n_changes); + if (r == 0) + r = q; + +@@ -1916,7 +1926,7 @@ static int install_context_apply( + if (i->type != UNIT_FILE_TYPE_REGULAR) + continue; + +- q = install_info_apply(i, paths, config_path, force, changes, n_changes); ++ q = install_info_apply(scope, i, paths, config_path, force, changes, n_changes); + if (r >= 0) { + if (q < 0) + r = q; +@@ -3324,10 +3334,11 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { + DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); + + static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = { +- [UNIT_FILE_SYMLINK] = "symlink", +- [UNIT_FILE_UNLINK] = "unlink", +- [UNIT_FILE_IS_MASKED] = "masked", +- [UNIT_FILE_IS_DANGLING] = "dangling", ++ [UNIT_FILE_SYMLINK] = "symlink", ++ [UNIT_FILE_UNLINK] = "unlink", ++ [UNIT_FILE_IS_MASKED] = "masked", ++ [UNIT_FILE_IS_DANGLING] = "dangling", ++ [UNIT_FILE_DESTINATION_NOT_PRESENT] = "destination not present", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); +diff --git a/src/shared/install.h b/src/shared/install.h +index e452940991..f07bebb415 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -57,6 +57,7 @@ enum UnitFileChangeType { + UNIT_FILE_UNLINK, + UNIT_FILE_IS_MASKED, + UNIT_FILE_IS_DANGLING, ++ UNIT_FILE_DESTINATION_NOT_PRESENT, + _UNIT_FILE_CHANGE_TYPE_MAX, + _UNIT_FILE_CHANGE_TYPE_INVALID = INT_MIN + }; diff --git a/SOURCES/0590-test-install-root-add-test-for-unknown-WantedBy-targ.patch b/SOURCES/0590-test-install-root-add-test-for-unknown-WantedBy-targ.patch new file mode 100644 index 0000000..10b11cc --- /dev/null +++ b/SOURCES/0590-test-install-root-add-test-for-unknown-WantedBy-targ.patch @@ -0,0 +1,56 @@ +From 430445a936cdb4c32c55affdfdd94b7eb910d5e6 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Wed, 31 Mar 2021 10:38:00 +0200 +Subject: [PATCH] test-install-root: add test for unknown WantedBy= target + +(cherry picked from commit 8adbad370f522831dd9246fe272caf37ce748d4a) + +Related: #1835351 +--- + src/test/test-install-root.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +index f8b41b04db..73e1e0ae03 100644 +--- a/src/test/test-install-root.c ++++ b/src/test/test-install-root.c +@@ -20,6 +20,7 @@ static void test_basic_mask_and_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/a.service"); + assert_se(write_string_file(p, +@@ -147,6 +148,31 @@ static void test_basic_mask_and_enable(const char *root) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ /* Test enabling with unknown dependency target */ ++ ++ p = strjoina(root, "/usr/lib/systemd/system/f.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=x.target\n", WRITE_STRING_FILE_CREATE) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("f.service"), &changes, &n_changes) == 1); ++ assert_se(n_changes == 2); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/f.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/x.target.wants/f.service"); ++ assert_se(streq(changes[0].path, p)); ++ assert_se(changes[1].type == UNIT_FILE_DESTINATION_NOT_PRESENT); ++ p = strjoina(root, "/usr/lib/systemd/system/f.service"); ++ assert_se(streq(changes[1].source, p)); ++ assert_se(streq(changes[1].path, "x.target")); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "f.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + } + + static void test_linked_units(const char *root) { diff --git a/SOURCES/0591-ceph-is-a-network-filesystem.patch b/SOURCES/0591-ceph-is-a-network-filesystem.patch new file mode 100644 index 0000000..78f408c --- /dev/null +++ b/SOURCES/0591-ceph-is-a-network-filesystem.patch @@ -0,0 +1,24 @@ +From d284fd2b036ed874f9f38da63f1ab4e9fd9e96a3 Mon Sep 17 00:00:00 2001 +From: Jonas Jelten +Date: Thu, 17 Oct 2019 12:10:13 +0200 +Subject: [PATCH] ceph is a network filesystem + +(cherry picked from commit c4742de6d801b125abf3c4d1c710280f51d7c701) + +Resolves: #1952013 +--- + src/basic/mount-util.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c +index be26bb5ec1..45348bf878 100644 +--- a/src/basic/mount-util.c ++++ b/src/basic/mount-util.c +@@ -608,6 +608,7 @@ bool fstype_is_network(const char *fstype) { + + return STR_IN_SET(fstype, + "afs", ++ "ceph", + "cifs", + "smb3", + "smbfs", diff --git a/SOURCES/0592-sysctl-set-kernel.core_pipe_limit-16.patch b/SOURCES/0592-sysctl-set-kernel.core_pipe_limit-16.patch new file mode 100644 index 0000000..a3b7073 --- /dev/null +++ b/SOURCES/0592-sysctl-set-kernel.core_pipe_limit-16.patch @@ -0,0 +1,49 @@ +From 8bdc512d2651b4600f7e744b06633a7524b64346 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 12 Oct 2020 16:31:42 +0200 +Subject: [PATCH] sysctl: set kernel.core_pipe_limit=16 + +We need to make sure that our coredump pattern handler manages to read +process metadata from /proc/$PID/ before the kernel reaps the crashed +process. By default the kernel will reap the process as soon as it can. +By setting kernel.core_pipe_limit to a non-zero the kernel will wait for +userspace to finish before reaping. + +We'll set the value to 16, which allows 16 crashes to be +processed in parallel. This matches the MaxConnections= setting in +systemd-coredump.socket. + +See: #17301 + +(This doesn't close 17301, since we probably should also gracefully +handle if /proc/$PID/ vanished already while our coredump handler runs, +just in case people loclly set the sysctl back to zero. i.e. we should +collect what we can and rather issue an incomplete log record than +none.) + +(cherry picked from commit 2a9b9323cd844baae3229e9dba67e478bee70654) + +Resolves: #1949729 +--- + sysctl.d/50-coredump.conf.in | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in +index ccd5c2cc56..8d6fbb718c 100644 +--- a/sysctl.d/50-coredump.conf.in ++++ b/sysctl.d/50-coredump.conf.in +@@ -10,3 +10,14 @@ + # setting below. + + kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %h %e ++ ++# Allow that 16 coredumps are dispatched in parallel by the kernel. We want to ++# be able to collect process metadata from /proc/%P/ while processing ++# coredumps, and thus need to make sure the crashed processes are not reaped ++# until we finished collecting what we need. The kernel default for this sysctl ++# is "0" which means the kernel doesn't wait for userspace processes to finish ++# processing before reaping the crashed processes — by setting this higher the ++# kernel will delay reaping until we are done, but only for the specified ++# number of crashes in parallel. The value of 16 is chosen to match ++# systemd-coredump.socket's MaxConnections= value. ++kernel.core_pipe_limit=16 diff --git a/SOURCES/0593-core-don-t-drop-timer-expired-but-not-yet-processed-.patch b/SOURCES/0593-core-don-t-drop-timer-expired-but-not-yet-processed-.patch new file mode 100644 index 0000000..d9774a8 --- /dev/null +++ b/SOURCES/0593-core-don-t-drop-timer-expired-but-not-yet-processed-.patch @@ -0,0 +1,116 @@ +From 73bf41a783edbff1b367e645956ed602de1889e2 Mon Sep 17 00:00:00 2001 +From: Insun +Date: Sun, 28 Oct 2018 21:26:13 +0900 +Subject: [PATCH] core: don't drop timer expired but not yet processed when + system date is changed + +There is difference between time set by the user and real elapsed time because of accuracy feature. +If you change the system date(or time) between these times, the timer drops. + +You can easily reproduce it with the following command. +----------------------------------------------------------- +$ systemd-run --on-active=3s ls; sleep 3; date -s "`date`" +----------------------------------------------------------- + +In the following command, the problem is rarely reproduced. But it exists. +--------------------------------------------------------------------------------------------- +$ systemd-run --on-active=3s --timer-property=AccuracySec=1us ls ; sleep 1; date -s "`date`" +--------------------------------------------------------------------------------------------- + +Note : Global AccuracySec value. +---------------------------------------------------------------------- +$ cat /etc/systemd/system.conf +DefaultTimerAccuracySec=1min +---------------------------------------------------------------------- + +(cherry picked from commit fee04d7f3ab810e99b97535ca5fda2f9517acda9) + +Related: #1899402 +--- + src/core/timer.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/src/core/timer.c b/src/core/timer.c +index 281ac7f97f..ef240a6f19 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -262,7 +262,7 @@ static void timer_set_state(Timer *t, TimerState state) { + unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0); + } + +-static void timer_enter_waiting(Timer *t, bool initial); ++static void timer_enter_waiting(Timer *t, bool initial, bool time_change); + + static int timer_coldplug(Unit *u) { + Timer *t = TIMER(u); +@@ -274,7 +274,7 @@ static int timer_coldplug(Unit *u) { + return 0; + + if (t->deserialized_state == TIMER_WAITING) +- timer_enter_waiting(t, false); ++ timer_enter_waiting(t, false, false); + else + timer_set_state(t, t->deserialized_state); + +@@ -334,7 +334,7 @@ static void add_random(Timer *t, usec_t *v) { + log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0)); + } + +-static void timer_enter_waiting(Timer *t, bool initial) { ++static void timer_enter_waiting(Timer *t, bool initial, bool time_change) { + bool found_monotonic = false, found_realtime = false; + bool leave_around = false; + triple_timestamp ts; +@@ -444,7 +444,7 @@ static void timer_enter_waiting(Timer *t, bool initial) { + + v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value); + +- if (!initial && ++ if (!initial && !time_change && + v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)) && + IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) { + /* This is a one time trigger, disable it now */ +@@ -642,7 +642,7 @@ static int timer_start(Unit *u) { + } + + t->result = TIMER_SUCCESS; +- timer_enter_waiting(t, true); ++ timer_enter_waiting(t, true, false); + return 1; + } + +@@ -764,14 +764,14 @@ static void timer_trigger_notify(Unit *u, Unit *other) { + case TIMER_ELAPSED: + + /* Recalculate sleep time */ +- timer_enter_waiting(t, false); ++ timer_enter_waiting(t, false, false); + break; + + case TIMER_RUNNING: + + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) { + log_unit_debug(UNIT(t), "Got notified about unit deactivation."); +- timer_enter_waiting(t, false); ++ timer_enter_waiting(t, false, false); + } + break; + +@@ -813,7 +813,7 @@ static void timer_time_change(Unit *u) { + t->last_trigger.realtime = ts; + + log_unit_debug(u, "Time change, recalculating next elapse."); +- timer_enter_waiting(t, false); ++ timer_enter_waiting(t, false, true); + } + + static void timer_timezone_change(Unit *u) { +@@ -825,7 +825,7 @@ static void timer_timezone_change(Unit *u) { + return; + + log_unit_debug(u, "Timezone change, recalculating next elapse."); +- timer_enter_waiting(t, false); ++ timer_enter_waiting(t, false, false); + } + + static const char* const timer_base_table[_TIMER_BASE_MAX] = { diff --git a/SOURCES/0594-core-Detect-initial-timer-state-from-serialized-data.patch b/SOURCES/0594-core-Detect-initial-timer-state-from-serialized-data.patch new file mode 100644 index 0000000..4334cb5 --- /dev/null +++ b/SOURCES/0594-core-Detect-initial-timer-state-from-serialized-data.patch @@ -0,0 +1,152 @@ +From 3d4280d0a487109f8f648147083baf573e4418a3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Koutn=C3=BD?= +Date: Fri, 2 Nov 2018 20:56:08 +0100 +Subject: [PATCH] core: Detect initial timer state from serialized data + +We keep a mark whether a single-shot timer was triggered in the caller's +variable initial. When such a timer elapses while we are +serializing/deserializing the inner state, we consider the timer +incorrectly as elapsed and don't trigger it later. + +This patch exploits last_trigger timestamp that we already serialize, +hence we can eliminate the argument initial completely. + +A reproducer for OnBootSec= timers: + cat >repro.c < + #include + #include + #include + #include + #include + #include + #include + + int main(int argc, char *argv[]) { + char command[1024]; + int pause; + + struct timespec now; + + while (1) { + usleep(rand() % 200000); // prevent periodic repeats + clock_gettime(CLOCK_MONOTONIC, &now); + printf("%i\n", now.tv_sec); + + system("rm -f $PWD/mark"); + snprintf(command, 1024, "systemd-run --user --on-boot=%i --timer-property=AccuracySec=100ms " + "touch $PWD/mark", now.tv_sec + 1); + system(command); + system("systemctl --user list-timers"); + pause = (1000000000 - now.tv_nsec)/1000 - 70000; // fiddle to hit the middle of reloading + usleep(pause > 0 ? pause : 0); + system("systemctl --user daemon-reload"); + sync(); + sleep(2); + if (open("./mark", 0) < 0) + if (errno == ENOENT) { + printf("mark file does not exist\n"); + break; + } + } + + return 0; + } + EOD + +(cherry picked from commit aa1f95d2647197eca84c33a0f10adaeada08467d) + +Resolves: #1899402 +--- + src/core/timer.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/src/core/timer.c b/src/core/timer.c +index ef240a6f19..1718ffc5a5 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -262,7 +262,7 @@ static void timer_set_state(Timer *t, TimerState state) { + unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0); + } + +-static void timer_enter_waiting(Timer *t, bool initial, bool time_change); ++static void timer_enter_waiting(Timer *t, bool time_change); + + static int timer_coldplug(Unit *u) { + Timer *t = TIMER(u); +@@ -274,7 +274,7 @@ static int timer_coldplug(Unit *u) { + return 0; + + if (t->deserialized_state == TIMER_WAITING) +- timer_enter_waiting(t, false, false); ++ timer_enter_waiting(t, false); + else + timer_set_state(t, t->deserialized_state); + +@@ -334,7 +334,7 @@ static void add_random(Timer *t, usec_t *v) { + log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0)); + } + +-static void timer_enter_waiting(Timer *t, bool initial, bool time_change) { ++static void timer_enter_waiting(Timer *t, bool time_change) { + bool found_monotonic = false, found_realtime = false; + bool leave_around = false; + triple_timestamp ts; +@@ -444,7 +444,8 @@ static void timer_enter_waiting(Timer *t, bool initial, bool time_change) { + + v->next_elapse = usec_add(usec_shift_clock(base, CLOCK_MONOTONIC, TIMER_MONOTONIC_CLOCK(t)), v->value); + +- if (!initial && !time_change && ++ if (dual_timestamp_is_set(&t->last_trigger) && ++ !time_change && + v->next_elapse < triple_timestamp_by_clock(&ts, TIMER_MONOTONIC_CLOCK(t)) && + IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) { + /* This is a one time trigger, disable it now */ +@@ -642,7 +643,7 @@ static int timer_start(Unit *u) { + } + + t->result = TIMER_SUCCESS; +- timer_enter_waiting(t, true, false); ++ timer_enter_waiting(t, false); + return 1; + } + +@@ -764,14 +765,14 @@ static void timer_trigger_notify(Unit *u, Unit *other) { + case TIMER_ELAPSED: + + /* Recalculate sleep time */ +- timer_enter_waiting(t, false, false); ++ timer_enter_waiting(t, false); + break; + + case TIMER_RUNNING: + + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) { + log_unit_debug(UNIT(t), "Got notified about unit deactivation."); +- timer_enter_waiting(t, false, false); ++ timer_enter_waiting(t, false); + } + break; + +@@ -813,7 +814,7 @@ static void timer_time_change(Unit *u) { + t->last_trigger.realtime = ts; + + log_unit_debug(u, "Time change, recalculating next elapse."); +- timer_enter_waiting(t, false, true); ++ timer_enter_waiting(t, true); + } + + static void timer_timezone_change(Unit *u) { +@@ -825,7 +826,7 @@ static void timer_timezone_change(Unit *u) { + return; + + log_unit_debug(u, "Timezone change, recalculating next elapse."); +- timer_enter_waiting(t, false, false); ++ timer_enter_waiting(t, false); + } + + static const char* const timer_base_table[_TIMER_BASE_MAX] = { diff --git a/SOURCES/0595-rc-local-order-after-network-online.target.patch b/SOURCES/0595-rc-local-order-after-network-online.target.patch new file mode 100644 index 0000000..438bb50 --- /dev/null +++ b/SOURCES/0595-rc-local-order-after-network-online.target.patch @@ -0,0 +1,29 @@ +From 8cd99937562cde7533519303a7a0ad1df749e075 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Thu, 11 Mar 2021 15:48:23 +0100 +Subject: [PATCH] rc-local: order after network-online.target + +I think this was the intent of commit 91b684c7300879a8d2006038f7d9185d92c3c3bf, +just network-online.target didn't exist back then. + +RHEL-only + +Resolves: #1934028 +--- + units/rc-local.service.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/units/rc-local.service.in b/units/rc-local.service.in +index 78ce69e0ae..74e83d8c07 100644 +--- a/units/rc-local.service.in ++++ b/units/rc-local.service.in +@@ -13,7 +13,8 @@ + Description=@RC_LOCAL_SCRIPT_PATH_START@ Compatibility + Documentation=man:systemd-rc-local-generator(8) + ConditionFileIsExecutable=@RC_LOCAL_SCRIPT_PATH_START@ +-After=network.target ++After=network-online.target ++Wants=network-online.target + + [Service] + Type=forking diff --git a/SOURCES/0596-set-core-ulimit-to-0-like-on-RHEL-7.patch b/SOURCES/0596-set-core-ulimit-to-0-like-on-RHEL-7.patch new file mode 100644 index 0000000..147d4eb --- /dev/null +++ b/SOURCES/0596-set-core-ulimit-to-0-like-on-RHEL-7.patch @@ -0,0 +1,25 @@ +From 830bd662276ee117e65a4b3d541f77e8b172eafd Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Mon, 25 Jan 2021 16:19:56 +0100 +Subject: [PATCH] set core ulimit to 0 like on RHEL-7 + +RHEL-only + +Resolves: #1905582 +--- + src/core/system.conf.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index 0d93fbf147..b4d6dfa15a 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -52,7 +52,7 @@ + #DefaultLimitFSIZE= + #DefaultLimitDATA= + #DefaultLimitSTACK= +-#DefaultLimitCORE= ++DefaultLimitCORE=0 + #DefaultLimitRSS= + #DefaultLimitNOFILE= + #DefaultLimitAS= diff --git a/SOURCES/0597-test-mountpointutil-util-do-not-assert-in-test_mnt_i.patch b/SOURCES/0597-test-mountpointutil-util-do-not-assert-in-test_mnt_i.patch new file mode 100644 index 0000000..216c7d1 --- /dev/null +++ b/SOURCES/0597-test-mountpointutil-util-do-not-assert-in-test_mnt_i.patch @@ -0,0 +1,129 @@ +From 4ad39b0531f550cde6e01df0801f177c08514c8b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 14 Sep 2020 17:58:03 +0200 +Subject: [PATCH] test-mountpointutil-util: do not assert in test_mnt_id() + +https://bugzilla.redhat.com/show_bug.cgi?id=1803070 + +I *think* this a kernel bug: the mnt_id as listed in /proc/self/mountinfo is different +than the one we get from /proc/self/fdinfo/. This only matters when both statx and +name_to_handle_at are unavailable and we hit the fallback path that goes through fdinfo: + +(gdb) !uname -r +5.6.19-200.fc31.ppc64le + +(gdb) !cat /proc/self/mountinfo +697 664 253:0 /var/lib/mock/fedora-31-ppc64le/root / rw,relatime shared:298 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota +698 697 253:0 /var/cache/mock/fedora-31-ppc64le/yum_cache /var/cache/yum rw,relatime shared:299 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota +699 697 253:0 /var/cache/mock/fedora-31-ppc64le/dnf_cache /var/cache/dnf rw,relatime shared:300 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota +700 697 0:32 /mock-selinux-plugin.7me9bfpi /proc/filesystems rw,nosuid,nodev shared:301 master:18 - tmpfs tmpfs rw,seclabel <========================================================== +701 697 0:41 / /sys ro,nosuid,nodev,noexec,relatime shared:302 - sysfs sysfs ro,seclabel +702 701 0:21 / /sys/fs/selinux ro,nosuid,nodev,noexec,relatime shared:306 master:8 - selinuxfs selinuxfs rw +703 697 0:42 / /dev rw,nosuid shared:303 - tmpfs tmpfs rw,seclabel,mode=755 +704 703 0:43 / /dev/shm rw,nosuid,nodev shared:304 - tmpfs tmpfs rw,seclabel +705 703 0:45 / /dev/pts rw,nosuid,noexec,relatime shared:307 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=666 +706 703 0:6 /btrfs-control /dev/btrfs-control rw,nosuid shared:308 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +707 703 0:6 /loop-control /dev/loop-control rw,nosuid shared:309 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +708 703 0:6 /loop0 /dev/loop0 rw,nosuid shared:310 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +709 703 0:6 /loop1 /dev/loop1 rw,nosuid shared:311 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +710 703 0:6 /loop10 /dev/loop10 rw,nosuid shared:312 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +711 703 0:6 /loop11 /dev/loop11 rw,nosuid shared:313 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +712 703 0:6 /loop2 /dev/loop2 rw,nosuid shared:314 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +713 703 0:6 /loop3 /dev/loop3 rw,nosuid shared:315 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +714 703 0:6 /loop4 /dev/loop4 rw,nosuid shared:316 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +715 703 0:6 /loop5 /dev/loop5 rw,nosuid shared:317 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +716 703 0:6 /loop6 /dev/loop6 rw,nosuid shared:318 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +717 703 0:6 /loop7 /dev/loop7 rw,nosuid shared:319 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +718 703 0:6 /loop8 /dev/loop8 rw,nosuid shared:320 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +719 703 0:6 /loop9 /dev/loop9 rw,nosuid shared:321 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755 +720 697 0:44 / /run rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755 +721 720 0:25 /systemd/nspawn/propagate/9cc8a155d0244558b273f773d2b92142 /run/systemd/nspawn/incoming ro master:12 - tmpfs tmpfs rw,seclabel,mode=755 +722 697 0:32 /mock-resolv.dvml91hp /etc/resolv.conf rw,nosuid,nodev shared:322 master:18 - tmpfs tmpfs rw,seclabel +725 697 0:47 / /proc rw,nosuid,nodev,noexec,relatime shared:323 - proc proc rw +603 725 0:47 /sys /proc/sys ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw +604 725 0:44 /systemd/inaccessible/reg /proc/kallsyms ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755 +605 725 0:44 /systemd/inaccessible/reg /proc/kcore ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755 +606 725 0:44 /systemd/inaccessible/reg /proc/keys ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755 +607 725 0:44 /systemd/inaccessible/reg /proc/sysrq-trigger ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755 +608 725 0:44 /systemd/inaccessible/reg /proc/timer_list ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755 +609 725 0:47 /bus /proc/bus ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw +610 725 0:47 /fs /proc/fs ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw +611 725 0:47 /irq /proc/irq ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw +612 725 0:47 /scsi /proc/scsi ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw +613 703 0:46 / /dev/mqueue rw,nosuid,nodev,noexec,relatime shared:324 - mqueue mqueue rw,seclabel +614 701 0:26 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:325 - cgroup2 cgroup rw,seclabel,nsdelegate +615 603 0:44 /.#proc-sys-kernel-random-boot-id4fbdce67af46d1c2//deleted /proc/sys/kernel/random/boot_id ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755 +616 725 0:44 /.#proc-sys-kernel-random-boot-id4fbdce67af46d1c2//deleted /proc/sys/kernel/random/boot_id rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755 +617 725 0:44 /.#proc-kmsg5b7a8bcfe6717139//deleted /proc/kmsg rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755 + +The test process does +name_to_handle_at("/proc/filesystems") which returns -EOPNOTSUPP, and then +openat(AT_FDCWD, "/proc/filesystems") which returns 4, and then +read(open("/proc/self/fdinfo/4", ...)) which gives +"pos:\t0\nflags:\t012100000\nmnt_id:\t725\n" + +and the "725" is clearly inconsistent with "700" in /proc/self/mountinfo. + +We could either drop the fallback path (and fail name_to_handle_at() is not +avaliable) or ignore the error in the test. Not sure what is better. I think +this issue only occurs sometimes and with older kernels, so probably continuing +with the current flaky implementation is better than ripping out the fallback. + +Another strace: +writev(2, [{iov_base="mnt ids of /proc/sys is 603", iov_len=27}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/sys is 603 +) = 28 +name_to_handle_at(AT_FDCWD, "/", {handle_bytes=128 => 12, handle_type=129, f_handle=0x52748401000000008b93e20d}, [697], 0) = 0 +writev(2, [{iov_base="mnt ids of / is 697", iov_len=19}, {iov_base="\n", iov_len=1}], 2mnt ids of / is 697 +) = 20 +name_to_handle_at(AT_FDCWD, "/proc/kcore", {handle_bytes=128 => 12, handle_type=1, f_handle=0x92ddcfcd2e802d0100000000}, [605], 0) = 0 +writev(2, [{iov_base="mnt ids of /proc/kcore is 605", iov_len=29}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/kcore is 605 +) = 30 +name_to_handle_at(AT_FDCWD, "/dev", {handle_bytes=128 => 12, handle_type=1, f_handle=0x8ae269160c802d0100000000}, [703], 0) = 0 +writev(2, [{iov_base="mnt ids of /dev is 703", iov_len=22}, {iov_base="\n", iov_len=1}], 2mnt ids of /dev is 703 +) = 23 +name_to_handle_at(AT_FDCWD, "/proc/filesystems", {handle_bytes=128}, 0x7fffe36ddb84, 0) = -1 EOPNOTSUPP (Operation not supported) +openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH) = 4 +openat(AT_FDCWD, "/proc/self/fdinfo/4", O_RDONLY|O_CLOEXEC) = 5 +fstat(5, {st_mode=S_IFREG|0400, st_size=0, ...}) = 0 +fstat(5, {st_mode=S_IFREG|0400, st_size=0, ...}) = 0 +read(5, "pos:\t0\nflags:\t012100000\nmnt_id:\t725\n", 2048) = 36 +read(5, "", 1024) = 0 +close(5) = 0 +close(4) = 0 +writev(2, [{iov_base="mnt ids of /proc/filesystems are 700, 725", iov_len=41}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/filesystems are 700, 725 +) = 42 +writev(2, [{iov_base="the other path for mnt id 725 is /proc", iov_len=38}, {iov_base="\n", iov_len=1}], 2the other path for mnt id 725 is /proc +) = 39 +writev(2, [{iov_base="Assertion 'path_equal(p, t)' failed at src/test/test-mountpoint-util.c:94, function test_mnt_id(). Aborting.", iov_len=108}, {iov_base="\n", iov_len=1}], 2Assertion 'path_equal(p, t)' failed at src/test/test-mountpoint-util.c:94, function test_mnt_id(). Aborting. +) = 109 +rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0 +rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [], 8) = 0 +getpid() = 20 +gettid() = 20 +tgkill(20, 20, SIGABRT) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 + +Resolves: #1910425 +--- + src/test/test-mount-util.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/test/test-mount-util.c b/src/test/test-mount-util.c +index c10e1681fb..991d165fc3 100644 +--- a/src/test/test-mount-util.c ++++ b/src/test/test-mount-util.c +@@ -74,7 +74,13 @@ static void test_mnt_id(void) { + + /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really + * the case */ +- assert_se(path_equal_ptr(hashmap_get(h, INT_TO_PTR(mnt_id2)), p)); ++ char *t = hashmap_get(h, INT_TO_PTR(mnt_id2)); ++ log_debug("Path for mnt id %i from /proc/self/mountinfo is %s\n", mnt_id2, t); ++ ++ if (!path_equal(p, t)) ++ /* Apparent kernel bug in /proc/self/fdinfo */ ++ log_warning("Bad mount id given for %s: %d, should be %d", ++ p, mnt_id2, mnt_id); + } + + hashmap_free_free(h); diff --git a/SOURCES/0598-remove-a-left-over-break.patch b/SOURCES/0598-remove-a-left-over-break.patch new file mode 100644 index 0000000..7d68ff0 --- /dev/null +++ b/SOURCES/0598-remove-a-left-over-break.patch @@ -0,0 +1,29 @@ +From 5944138a54017fc8f1f4c878a1eea96ea18736c4 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Fri, 25 Jun 2021 10:42:53 +0200 +Subject: [PATCH] remove a left-over break + +By the "same logic as above...", we want to continue to fallback here, +but the break prohibits that. + +This is a follow-up for ee1aa61c4710ae567a2b844e0f0bb8cb0456ab8c . + +(cherry picked from commit 99df1cb6f50875db513a5b45f18191460a150f3d) + +Related: #1970860 +--- + src/basic/copy.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/basic/copy.c b/src/basic/copy.c +index a48c42c5c6..1a0db29ac9 100644 +--- a/src/basic/copy.c ++++ b/src/basic/copy.c +@@ -218,7 +218,6 @@ int copy_bytes_full( + break; + + try_sendfile = try_splice = false; /* same logic as above for copy_file_range() */ +- break; + } else + /* Success! */ + goto next; diff --git a/SOURCES/0599-basic-unit-name-do-not-use-strdupa-on-a-path.patch b/SOURCES/0599-basic-unit-name-do-not-use-strdupa-on-a-path.patch new file mode 100644 index 0000000..adf5607 --- /dev/null +++ b/SOURCES/0599-basic-unit-name-do-not-use-strdupa-on-a-path.patch @@ -0,0 +1,65 @@ +From c5d2964d498da0ac06799e5f040de74a0f5d2deb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 23 Jun 2021 11:46:41 +0200 +Subject: [PATCH] basic/unit-name: do not use strdupa() on a path + +The path may have unbounded length, for example through a fuse mount. + +CVE-2021-33910: attacked controlled alloca() leads to crash in systemd and +ultimately a kernel panic. Systemd parses the content of /proc/self/mountinfo +and each mountpoint is passed to mount_setup_unit(), which calls +unit_name_path_escape() underneath. A local attacker who is able to mount a +filesystem with a very long path can crash systemd and the whole system. + +https://bugzilla.redhat.com/show_bug.cgi?id=1970887 + +The resulting string length is bounded by UNIT_NAME_MAX, which is 256. But we +can't easily check the length after simplification before doing the +simplification, which in turns uses a copy of the string we can write to. +So we can't reject paths that are too long before doing the duplication. +Hence the most obvious solution is to switch back to strdup(), as before +7410616cd9dbbec97cf98d75324da5cda2b2f7a2. + +Resolves: #1974700 + +(cherry picked from commit 441e0115646d54f080e5c3bb0ba477c892861ab9) +--- + src/basic/unit-name.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c +index 1b81fe268f..614eb8649b 100644 +--- a/src/basic/unit-name.c ++++ b/src/basic/unit-name.c +@@ -369,12 +369,13 @@ int unit_name_unescape(const char *f, char **ret) { + } + + int unit_name_path_escape(const char *f, char **ret) { +- char *p, *s; ++ _cleanup_free_ char *p = NULL; ++ char *s; + + assert(f); + assert(ret); + +- p = strdupa(f); ++ p = strdup(f); + if (!p) + return -ENOMEM; + +@@ -386,13 +387,9 @@ int unit_name_path_escape(const char *f, char **ret) { + if (!path_is_normalized(p)) + return -EINVAL; + +- /* Truncate trailing slashes */ ++ /* Truncate trailing slashes and skip leading slashes */ + delete_trailing_chars(p, "/"); +- +- /* Truncate leading slashes */ +- p = skip_leading_chars(p, "/"); +- +- s = unit_name_escape(p); ++ s = unit_name_escape(skip_leading_chars(p, "/")); + } + if (!s) + return -ENOMEM; diff --git a/SOURCES/0600-sd-event-change-ordering-of-pending-ratelimited-even.patch b/SOURCES/0600-sd-event-change-ordering-of-pending-ratelimited-even.patch new file mode 100644 index 0000000..84836ab --- /dev/null +++ b/SOURCES/0600-sd-event-change-ordering-of-pending-ratelimited-even.patch @@ -0,0 +1,96 @@ +From f863f89d8a5cbb47676d5114e349918c4e009fe5 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 8 Jun 2021 00:07:51 -0700 +Subject: [PATCH] sd-event: change ordering of pending/ratelimited events + +Instead of ordering non-pending before pending we should order +"non-pending OR ratelimited" before "pending AND not-ratelimited". +This fixes a bug where ratelimited events were ordered at the end of the +priority queue and could be stuck there for an indeterminate amount of +time. + +(cherry picked from commit 81107b8419c39f726fd2805517a5b9faab204e59) + +Related: #1968528 +--- + src/libsystemd/sd-event/sd-event.c | 48 +++++++++++++----------------- + 1 file changed, 20 insertions(+), 28 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index be912d94e3..3e77f4e810 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -427,25 +427,6 @@ static usec_t time_event_source_next(const sd_event_source *s) { + return USEC_INFINITY; + } + +-static int earliest_time_prioq_compare(const void *a, const void *b) { +- const sd_event_source *x = a, *y = b; +- +- /* Enabled ones first */ +- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) +- return -1; +- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) +- return 1; +- +- /* Move the pending ones to the end */ +- if (!x->pending && y->pending) +- return -1; +- if (x->pending && !y->pending) +- return 1; +- +- /* Order by time */ +- return CMP(time_event_source_next(x), time_event_source_next(y)); +-} +- + static usec_t time_event_source_latest(const sd_event_source *s) { + assert(s); + +@@ -464,7 +445,15 @@ static usec_t time_event_source_latest(const sd_event_source *s) { + return USEC_INFINITY; + } + +-static int latest_time_prioq_compare(const void *a, const void *b) { ++static bool event_source_timer_candidate(const sd_event_source *s) { ++ assert(s); ++ ++ /* Returns true for event sources that either are not pending yet (i.e. where it's worth to mark them pending) ++ * or which are currently ratelimited (i.e. where it's worth leaving the ratelimited state) */ ++ return !s->pending || s->ratelimited; ++} ++ ++static int time_prioq_compare(const void *a, const void *b, usec_t (*time_func)(const sd_event_source *s)) { + const sd_event_source *x = a, *y = b; + + /* Enabled ones first */ +@@ -473,19 +462,22 @@ static int latest_time_prioq_compare(const void *a, const void *b) { + if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) + return 1; + +- /* Move the pending ones to the end */ +- if (!x->pending && y->pending) ++ /* Order "non-pending OR ratelimited" before "pending AND not-ratelimited" */ ++ if (event_source_timer_candidate(x) && !event_source_timer_candidate(y)) + return -1; +- if (x->pending && !y->pending) ++ if (!event_source_timer_candidate(x) && event_source_timer_candidate(y)) + return 1; + + /* Order by time */ +- if (time_event_source_latest(x) < time_event_source_latest(y)) +- return -1; +- if (time_event_source_latest(x) > time_event_source_latest(y)) +- return 1; ++ return CMP(time_func(x), time_func(y)); ++} + +- return 0; ++static int earliest_time_prioq_compare(const void *a, const void *b) { ++ return time_prioq_compare(a, b, time_event_source_next); ++} ++ ++static int latest_time_prioq_compare(const void *a, const void *b) { ++ return time_prioq_compare(a, b, time_event_source_latest); + } + + static int exit_prioq_compare(const void *a, const void *b) { diff --git a/SOURCES/0601-sd-event-drop-unnecessary-else.patch b/SOURCES/0601-sd-event-drop-unnecessary-else.patch new file mode 100644 index 0000000..d63606d --- /dev/null +++ b/SOURCES/0601-sd-event-drop-unnecessary-else.patch @@ -0,0 +1,27 @@ +From 9faf4d1a39b7fc8c9f986a808e1c0d3ed9b44357 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 15 Jun 2021 00:44:04 +0900 +Subject: [PATCH] sd-event: drop unnecessary "else" + +(cherry picked from commit 7e2bf71ca3638e36ee33215ceee386ba8013da6d) + +Related: #1968528 +--- + src/libsystemd/sd-event/sd-event.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 3e77f4e810..2b0b76aa1c 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2883,8 +2883,8 @@ static int event_arm_timer( + + if (!d->needs_rearm) + return 0; +- else +- d->needs_rearm = false; ++ ++ d->needs_rearm = false; + + a = prioq_peek(d->earliest); + if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) { diff --git a/SOURCES/0602-sd-event-use-CMP-macro.patch b/SOURCES/0602-sd-event-use-CMP-macro.patch new file mode 100644 index 0000000..2cf6223 --- /dev/null +++ b/SOURCES/0602-sd-event-use-CMP-macro.patch @@ -0,0 +1,90 @@ +From 7419222d3811d60c0a8f5ea27778108a1ca8ee71 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 15 Jun 2021 00:51:33 +0900 +Subject: [PATCH] sd-event: use CMP() macro + +(cherry picked from commit 06e131477d82b83c5d516e66d6e413affd7c774a) + +Related: #1968528 +--- + src/libsystemd/sd-event/sd-event.c | 37 ++++++++++++++---------------- + 1 file changed, 17 insertions(+), 20 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 2b0b76aa1c..6a20b658e4 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -358,10 +358,9 @@ static int pending_prioq_compare(const void *a, const void *b) { + assert(y->pending); + + /* Enabled ones first */ +- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) +- return -1; +- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) +- return 1; ++ r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF); ++ if (r != 0) ++ return r; + + /* Non rate-limited ones first. */ + r = CMP(!!x->ratelimited, !!y->ratelimited); +@@ -385,10 +384,9 @@ static int prepare_prioq_compare(const void *a, const void *b) { + assert(y->prepare); + + /* Enabled ones first */ +- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) +- return -1; +- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) +- return 1; ++ r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF); ++ if (r != 0) ++ return r; + + /* Non rate-limited ones first. */ + r = CMP(!!x->ratelimited, !!y->ratelimited); +@@ -455,18 +453,17 @@ static bool event_source_timer_candidate(const sd_event_source *s) { + + static int time_prioq_compare(const void *a, const void *b, usec_t (*time_func)(const sd_event_source *s)) { + const sd_event_source *x = a, *y = b; ++ int r; + + /* Enabled ones first */ +- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) +- return -1; +- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) +- return 1; ++ r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF); ++ if (r != 0) ++ return r; + + /* Order "non-pending OR ratelimited" before "pending AND not-ratelimited" */ +- if (event_source_timer_candidate(x) && !event_source_timer_candidate(y)) +- return -1; +- if (!event_source_timer_candidate(x) && event_source_timer_candidate(y)) +- return 1; ++ r = CMP(!event_source_timer_candidate(x), !event_source_timer_candidate(y)); ++ if (r != 0) ++ return r; + + /* Order by time */ + return CMP(time_func(x), time_func(y)); +@@ -482,15 +479,15 @@ static int latest_time_prioq_compare(const void *a, const void *b) { + + static int exit_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; ++ int r; + + assert(x->type == SOURCE_EXIT); + assert(y->type == SOURCE_EXIT); + + /* Enabled ones first */ +- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) +- return -1; +- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) +- return 1; ++ r = CMP(x->enabled == SD_EVENT_OFF, y->enabled == SD_EVENT_OFF); ++ if (r != 0) ++ return r; + + /* Lower priority values first */ + if (x->priority < y->priority) diff --git a/SOURCES/0603-sd-event-use-usec_add.patch b/SOURCES/0603-sd-event-use-usec_add.patch new file mode 100644 index 0000000..c155350 --- /dev/null +++ b/SOURCES/0603-sd-event-use-usec_add.patch @@ -0,0 +1,27 @@ +From b79e00d8f97b8c959c5b17f0547c680f86dd9132 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 15 Jun 2021 01:01:48 +0900 +Subject: [PATCH] sd-event: use usec_add() + +(cherry picked from commit a595fb5ca9c69c589e758e9ebe3b70ac90450ba3) + +Related: #1968528 +--- + src/libsystemd/sd-event/sd-event.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 6a20b658e4..f675c09d84 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -3514,8 +3514,8 @@ static int arm_watchdog(sd_event *e) { + assert(e->watchdog_fd >= 0); + + t = sleep_between(e, +- e->watchdog_last + (e->watchdog_period / 2), +- e->watchdog_last + (e->watchdog_period * 3 / 4)); ++ usec_add(e->watchdog_last, (e->watchdog_period / 2)), ++ usec_add(e->watchdog_last, (e->watchdog_period * 3 / 4))); + + timespec_store(&its.it_value, t); + diff --git a/SOURCES/0604-sd-event-make-event_source_time_prioq_reshuffle-acce.patch b/SOURCES/0604-sd-event-make-event_source_time_prioq_reshuffle-acce.patch new file mode 100644 index 0000000..13ed16d --- /dev/null +++ b/SOURCES/0604-sd-event-make-event_source_time_prioq_reshuffle-acce.patch @@ -0,0 +1,40 @@ +From bf370d05bbc8c4d91c8c2b455116e59a24e48911 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 15 Jun 2021 02:03:02 +0900 +Subject: [PATCH] sd-event: make event_source_time_prioq_reshuffle() accept all + event source type + +But it does nothing for an event source which is neither a timer nor +ratelimited. + +(cherry picked from commit 5c08c7ab23dbf02aaf4e4bbae8e08a195da230a4) + +Related: #1968528 +--- + src/libsystemd/sd-event/sd-event.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index f675c09d84..ae46392901 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -954,14 +954,15 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) { + assert(s); + + /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, +- * pending, enable state. Makes sure the two prioq's are ordered properly again. */ ++ * pending, enable state, and ratelimiting state. Makes sure the two prioq's are ordered ++ * properly again. */ + + if (s->ratelimited) + d = &s->event->monotonic; +- else { +- assert(EVENT_SOURCE_IS_TIME(s->type)); ++ else if (EVENT_SOURCE_IS_TIME(s->type)) + assert_se(d = event_get_clock_data(s->event, s->type)); +- } ++ else ++ return; /* no-op for an event source which is neither a timer nor ratelimited. */ + + prioq_reshuffle(d->earliest, s, &s->earliest_index); + prioq_reshuffle(d->latest, s, &s->latest_index); diff --git a/SOURCES/0605-sd-event-always-reshuffle-time-prioq-on-changing-onl.patch b/SOURCES/0605-sd-event-always-reshuffle-time-prioq-on-changing-onl.patch new file mode 100644 index 0000000..23178cd --- /dev/null +++ b/SOURCES/0605-sd-event-always-reshuffle-time-prioq-on-changing-onl.patch @@ -0,0 +1,90 @@ +From 1ce5187fb47bec57de4d8d3fd0068072228ec5e3 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 15 Jun 2021 02:13:59 +0900 +Subject: [PATCH] sd-event: always reshuffle time prioq on changing + online/offline state + +Before 81107b8419c39f726fd2805517a5b9faab204e59, the compare functions +for the latest or earliest prioq did not handle ratelimited flag. +So, it was ok to not reshuffle the time prioq when changing the flag. + +But now, those two compare functions also compare the source is +ratelimited or not. So, it is necessary to reshuffle the time prioq +after changing the ratelimited flag. + +Hopefully fixes #19903. + +(cherry picked from commit 2115b9b6629eeba7bc9f42f757f38205febb1cb7) + +Related: #1968528 +--- + src/libsystemd/sd-event/sd-event.c | 33 ++++++++++-------------------- + 1 file changed, 11 insertions(+), 22 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index ae46392901..f78da00c3a 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -2390,14 +2390,6 @@ static int event_source_offline( + source_io_unregister(s); + break; + +- case SOURCE_TIME_REALTIME: +- case SOURCE_TIME_BOOTTIME: +- case SOURCE_TIME_MONOTONIC: +- case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: +- event_source_time_prioq_reshuffle(s); +- break; +- + case SOURCE_SIGNAL: + event_gc_signal_data(s->event, &s->priority, s->signal.sig); + break; +@@ -2415,6 +2407,11 @@ static int event_source_offline( + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); + break; + ++ case SOURCE_TIME_REALTIME: ++ case SOURCE_TIME_BOOTTIME: ++ case SOURCE_TIME_MONOTONIC: ++ case SOURCE_TIME_REALTIME_ALARM: ++ case SOURCE_TIME_BOOTTIME_ALARM: + case SOURCE_DEFER: + case SOURCE_POST: + case SOURCE_INOTIFY: +@@ -2424,6 +2421,9 @@ static int event_source_offline( + assert_not_reached("Wut? I shouldn't exist."); + } + ++ /* Always reshuffle time prioq, as the ratelimited flag may be changed. */ ++ event_source_time_prioq_reshuffle(s); ++ + return 1; + } + +@@ -2505,22 +2505,11 @@ static int event_source_online( + s->ratelimited = ratelimited; + + /* Non-failing operations below */ +- switch (s->type) { +- case SOURCE_TIME_REALTIME: +- case SOURCE_TIME_BOOTTIME: +- case SOURCE_TIME_MONOTONIC: +- case SOURCE_TIME_REALTIME_ALARM: +- case SOURCE_TIME_BOOTTIME_ALARM: +- event_source_time_prioq_reshuffle(s); +- break; +- +- case SOURCE_EXIT: ++ if (s->type == SOURCE_EXIT) + prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); +- break; + +- default: +- break; +- } ++ /* Always reshuffle time prioq, as the ratelimited flag may be changed. */ ++ event_source_time_prioq_reshuffle(s); + + return 1; + } diff --git a/SOURCES/0606-ci-run-unit-tests-on-z-stream-branches-as-well.patch b/SOURCES/0606-ci-run-unit-tests-on-z-stream-branches-as-well.patch new file mode 100644 index 0000000..91d1c80 --- /dev/null +++ b/SOURCES/0606-ci-run-unit-tests-on-z-stream-branches-as-well.patch @@ -0,0 +1,27 @@ +From 68cedfd41f1ea3eda34b0023e951649b92953709 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Thu, 15 Jul 2021 12:27:33 +0200 +Subject: [PATCH] ci: run unit tests on z-stream branches as well + +Resolves: #1970860 +rhel-only +--- + .github/workflows/unit_tests.yml | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml +index 15f5127a75..428bde4ed8 100644 +--- a/.github/workflows/unit_tests.yml ++++ b/.github/workflows/unit_tests.yml +@@ -2,10 +2,7 @@ + # vi: ts=2 sw=2 et: + # + name: Unit tests +-on: +- pull_request: +- branches: +- - master ++on: [pull_request] + + jobs: + build: diff --git a/SOURCES/0607-ci-drop-forgotten-Travis-references.patch b/SOURCES/0607-ci-drop-forgotten-Travis-references.patch new file mode 100644 index 0000000..4537e2e --- /dev/null +++ b/SOURCES/0607-ci-drop-forgotten-Travis-references.patch @@ -0,0 +1,32 @@ +From 9bb57b7bed93e79f578e7c5b0c95f1f454e5d829 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 3 Mar 2021 12:33:38 +0100 +Subject: [PATCH] ci: drop forgotten Travis references + +rhel-only +Related: #1934504 +--- + .github/workflows/unit_tests.sh | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh +index ea4f7e7592..43882b27da 100755 +--- a/.github/workflows/unit_tests.sh ++++ b/.github/workflows/unit_tests.sh +@@ -68,7 +68,7 @@ for phase in "${PHASES[@]}"; do + case $phase in + SETUP) + info "Setup phase" +- info "Using Travis $CENTOS_RELEASE" ++ info "Using $CENTOS_RELEASE image" + # Pull a Docker image and start a new container + docker pull quay.io/centos/centos:$CENTOS_RELEASE + info "Starting container $CONT_NAME" +@@ -110,7 +110,6 @@ for phase in "${PHASES[@]}"; do + docker exec --interactive=false \ + -e UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1 \ + -e ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 \ +- -e "TRAVIS=$TRAVIS" \ + -t $CONT_NAME \ + meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs + ;; diff --git a/SOURCES/0608-ci-run-unit-tests-on-CentOS-8-Stream-as-well.patch b/SOURCES/0608-ci-run-unit-tests-on-CentOS-8-Stream-as-well.patch new file mode 100644 index 0000000..159399a --- /dev/null +++ b/SOURCES/0608-ci-run-unit-tests-on-CentOS-8-Stream-as-well.patch @@ -0,0 +1,113 @@ +From ccde55a339d211af488b1f1c148597d7977a9bb8 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 3 Mar 2021 12:49:20 +0100 +Subject: [PATCH] ci: run unit tests on CentOS 8 Stream as well + +rhel-only +Related: #1934504 +--- + .github/workflows/unit_tests.sh | 52 +++++++++++++++++++++++++++++++- + .github/workflows/unit_tests.yml | 13 ++++---- + 2 files changed, 58 insertions(+), 7 deletions(-) + +diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh +index 43882b27da..8648e7149e 100755 +--- a/.github/workflows/unit_tests.sh ++++ b/.github/workflows/unit_tests.sh +@@ -58,6 +58,53 @@ CONFIGURE_OPTS=( + -Ddefault-hierarchy=legacy + ) + ++# CentOS 8 Stream still doesn't provide SRPMs, so we can't use dnf's builddep ++# command to fetch this list for us. Hopefully, we'll be able to get rid ++# of this in the future. ++# See: https://bugs.centos.org/view.php?id=16715 ++SYSTEMD_BUILD_DEPS=( ++ audit-libs-devel ++ bzip2-devel ++ cryptsetup-devel ++ dbus-devel ++ docbook-style-xsl ++ elfutils-devel ++ firewalld-filesystem ++ gcc ++ gcc-c++ ++ gettext ++ git ++ gnu-efi ++ gnu-efi-devel ++ gnutls-devel ++ gobject-introspection-devel ++ gperf ++ iptables-devel ++ kmod-devel ++ libacl-devel ++ libblkid-devel ++ libcap-devel ++ libcurl-devel ++ libgcrypt-devel ++ libgpg-error-devel ++ libidn2-devel ++ libmicrohttpd-devel ++ libmount-devel ++ libseccomp-devel ++ libselinux-devel ++ libxkbcommon-devel ++ libxslt ++ lz4 ++ lz4-devel ++ meson ++ pam-devel ++ pkgconf-pkg-config ++ python3-lxml ++ python36-devel ++ tree ++ xz-devel ++) ++ + function info() { + echo -e "\033[33;1m$1\033[0m" + } +@@ -85,7 +132,10 @@ for phase in "${PHASES[@]}"; do + # Upgrade the container to get the most recent environment + $DOCKER_EXEC dnf -y upgrade + # Install systemd's build dependencies +- $DOCKER_EXEC dnf -q -y --enablerepo "powertools" builddep systemd ++ if ! $DOCKER_EXEC dnf -q -y --enablerepo "powertools" builddep systemd; then ++ # See the $SYSTEMD_BUILD_DEPS above for reasoning ++ $DOCKER_EXEC dnf -q -y --enablerepo "powertools" install "${SYSTEMD_BUILD_DEPS[@]}" ++ fi + ;; + RUN|RUN_GCC) + info "Run phase" +diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml +index 428bde4ed8..b363118be8 100644 +--- a/.github/workflows/unit_tests.yml ++++ b/.github/workflows/unit_tests.yml +@@ -7,19 +7,20 @@ on: [pull_request] + jobs: + build: + runs-on: ubuntu-20.04 +- env: +- CENTOS_RELEASE: "centos8" +- CONT_NAME: "systemd-centos8-ci" + strategy: + fail-fast: false + matrix: +- run_phase: [GCC, GCC_ASAN] ++ image: [centos8, stream8] ++ phase: [GCC, GCC_ASAN] ++ env: ++ CONT_NAME: "systemd-centos8-ci" ++ CENTOS_RELEASE: ${{ matrix.image }} + steps: + - name: Repository checkout + uses: actions/checkout@v1 + - name: Install build dependencies + run: sudo -E .github/workflows/unit_tests.sh SETUP +- - name: Build & test (${{ matrix.run_phase }}) +- run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }} ++ - name: Build & test (${{ env.CENTOS_RELEASE }} / ${{ matrix.phase }}) ++ run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.phase }} + - name: Cleanup + run: sudo -E .github/workflows/unit_tests.sh CLEANUP diff --git a/SOURCES/0609-ci-add-missing-test-dependencies.patch b/SOURCES/0609-ci-add-missing-test-dependencies.patch new file mode 100644 index 0000000..86c6c62 --- /dev/null +++ b/SOURCES/0609-ci-add-missing-test-dependencies.patch @@ -0,0 +1,37 @@ +From 68555d26da9e46efbd70703b39a81cee601d265a Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Wed, 3 Mar 2021 13:14:02 +0100 +Subject: [PATCH] ci: add missing test dependencies + +rhel-only +Related: #1934504 +--- + .github/workflows/unit_tests.sh | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh +index 8648e7149e..ad4584ec1d 100755 +--- a/.github/workflows/unit_tests.sh ++++ b/.github/workflows/unit_tests.sh +@@ -6,7 +6,20 @@ CONT_NAME="${CONT_NAME:-centos-$CENTOS_RELEASE-$RANDOM}" + DOCKER_EXEC="${DOCKER_EXEC:-docker exec $CONT_NAME}" + DOCKER_RUN="${DOCKER_RUN:-docker run}" + REPO_ROOT="${REPO_ROOT:-$PWD}" +-ADDITIONAL_DEPS=(libasan libubsan net-tools strace nc e2fsprogs quota dnsmasq diffutils) ++ADDITIONAL_DEPS=( ++ diffutils ++ dnsmasq ++ e2fsprogs ++ hostname ++ libasan ++ libubsan ++ nc ++ net-tools ++ perl-IPC-SysV ++ perl-Time-HiRes ++ quota ++ strace ++) + # RHEL8 options + CONFIGURE_OPTS=( + -Dsysvinit-path=/etc/rc.d/init.d diff --git a/SOURCES/0610-meson-bump-timeout-for-test-udev-to-180s.patch b/SOURCES/0610-meson-bump-timeout-for-test-udev-to-180s.patch new file mode 100644 index 0000000..f750215 --- /dev/null +++ b/SOURCES/0610-meson-bump-timeout-for-test-udev-to-180s.patch @@ -0,0 +1,30 @@ +From 998041fbb2b4114f2f1df604cdebc4afbf682d63 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Fri, 18 Jan 2019 22:32:42 +0100 +Subject: [PATCH] meson: bump timeout for test-udev to 180s + +On some (mainly virtual) machines the last test takes more than 30 +seconds, which causes unnecessary fails, as the test itself is working +properly. + +(cherry picked from commit bb0e960448fce037f5b82b1829863da8ccbe636b) + +Related: #1934504 +--- + test/meson.build | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/test/meson.build b/test/meson.build +index 52e4fa2e3c..535354f3ab 100644 +--- a/test/meson.build ++++ b/test/meson.build +@@ -246,7 +246,8 @@ custom_target( + if perl.found() + udev_test_pl = find_program('udev-test.pl') + test('udev-test', +- udev_test_pl) ++ udev_test_pl, ++ timeout : 180) + else + message('Skipping udev-test because perl is not available') + endif diff --git a/SOURCES/0611-Added-option-check-inhibitors-for-non-tty-usage.patch b/SOURCES/0611-Added-option-check-inhibitors-for-non-tty-usage.patch new file mode 100644 index 0000000..c913f65 --- /dev/null +++ b/SOURCES/0611-Added-option-check-inhibitors-for-non-tty-usage.patch @@ -0,0 +1,222 @@ +From f875436b93c6c5e83f46ab32429c977db4f0b10c Mon Sep 17 00:00:00 2001 +From: Felix Stupp +Date: Thu, 29 Oct 2020 12:48:48 +0100 +Subject: [PATCH] Added option --check-inhibitors for non-tty usage + +As described in #2680, systemctl did ignore inhibitors if it is not +attached to a tty to allow scripts to ignore inhibitors automatically. +This pull request preserves this behavior but allows scripts to +explicit check inhibitors if required. + +The new parameter '--check-inhibitors=yes' enables this feature. +The old parameter '-i'/'--ignore-inhibitors' was deprecated in favor +of '--check-inhibitors=no', the default behaviour can be specified +with '--check-inhibitors=auto'. +The new parameter is also described in the documentations and shell +completions found here. + +(cherry picked from commit b8ebe378b49a31549b8531d4b3177095ef385d55) + +Related: #1269726 +--- + man/systemctl.xml | 38 ++++++++++++++++++++---------- + shell-completion/bash/systemctl.in | 7 ++++-- + shell-completion/zsh/_systemctl.in | 9 ++++++- + src/systemctl/systemctl.c | 37 +++++++++++++++++++++-------- + 4 files changed, 65 insertions(+), 26 deletions(-) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index ed60a0739f..9f0f4d46ea 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -323,23 +323,35 @@ + + + ++ ++ ++ ++ ++ When system shutdown or sleep state is request, this option controls how to deal with ++ inhibitor locks. It takes one of auto, yes or ++ no. Defaults to auto, which will behave like ++ yes for interactive invocations (i.e. from a TTY) and no ++ for non-interactive invocations. ++ yes will let the request respect inhibitor locks. ++ no will let the request ignore inhibitor locks. ++ ++ Applications can establish inhibitor locks to avoid that certain important operations ++ (such as CD burning or suchlike) are interrupted by system shutdown or a sleep state. Any user may ++ take these locks and privileged users may override these locks. ++ If any locks are taken, shutdown and sleep state requests will normally fail (unless privileged) ++ and a list of active locks is printed. ++ However, if no is specified or auto is specified on a ++ non-interactive requests, the established locks are ignored and not shown, and the operation ++ attempted anyway, possibly requiring additional privileges. ++ May be overriden by . ++ ++ ++ + + +- + + +- When system shutdown or a sleep state is requested, +- ignore inhibitor locks. Applications can establish inhibitor +- locks to avoid that certain important operations (such as CD +- burning or suchlike) are interrupted by system shutdown or a +- sleep state. Any user may take these locks and privileged +- users may override these locks. If any locks are taken, +- shutdown and sleep state requests will normally fail +- (regardless of whether privileged or not) and a list of active locks +- is printed. However, if +- is specified, the locks are ignored and not printed, and the +- operation attempted anyway, possibly requiring additional +- privileges. ++ Shortcut for . + + + +diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in +index ba51ae0d34..0c7afea57d 100644 +--- a/shell-completion/bash/systemctl.in ++++ b/shell-completion/bash/systemctl.in +@@ -111,9 +111,9 @@ _systemctl () { + [STANDALONE]='--all -a --reverse --after --before --defaults --force -f --full -l --global + --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall --now + --quiet -q --system --user --version --runtime --recursive -r --firmware-setup +- --show-types -i --ignore-inhibitors --plain --failed --value --fail --dry-run --wait' ++ --show-types --plain --failed --value --fail --dry-run --wait' + [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root +- --preset-mode -n --lines -o --output -M --machine --message' ++ --preset-mode -n --lines -o --output -M --machine --message --check-inhibitors' + ) + + if __contains_word "--user" ${COMP_WORDS[*]}; then +@@ -163,6 +163,9 @@ _systemctl () { + --machine|-M) + comps=$( __get_machines ) + ;; ++ --check-inhibitors) ++ comps='auto yes no' ++ ;; + esac + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 +diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in +index 9f576ed77d..b3c51cc843 100644 +--- a/shell-completion/zsh/_systemctl.in ++++ b/shell-completion/zsh/_systemctl.in +@@ -363,6 +363,13 @@ _job_modes() { + _values -s , "${_modes[@]}" + } + ++(( $+functions[_systemctl_check_inhibitors] )) || ++ _systemctl_check_inhibitors() { ++ local -a _modes ++ _modes=(auto yes no) ++ _values -s , "${_modes[@]}" ++ } ++ + # Build arguments for "systemctl" to be used in completion. + local -a _modes; _modes=("--user" "--system") + # Use the last mode (they are exclusive and the last one is used). +@@ -380,7 +387,7 @@ _arguments -s \ + '--before[Show units ordered before]' \ + {-l,--full}"[Don't ellipsize unit names on output]" \ + '--show-types[When showing sockets, show socket type]' \ +- {-i,--ignore-inhibitors}'[When executing a job, ignore jobs dependencies]' \ ++ '--check-inhibitors[Specify if inhibitors should be checked]:mode:_systemctl_check_inhibitors' \ + {-q,--quiet}'[Suppress output]' \ + '--no-block[Do not wait until operation finished]' \ + '--no-legend[Do not print a legend, i.e. the column headers and the footer with hints]' \ +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 8bec798373..8bcbf6bf4b 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -121,7 +121,7 @@ static bool arg_no_wall = false; + static bool arg_no_reload = false; + static bool arg_value = false; + static bool arg_show_types = false; +-static bool arg_ignore_inhibitors = false; ++static int arg_check_inhibitors = -1; + static bool arg_dry_run = false; + static bool arg_quiet = false; + static bool arg_full = false; +@@ -3313,17 +3313,19 @@ static int logind_check_inhibitors(enum action a) { + char **s; + int r; + +- if (arg_ignore_inhibitors || arg_force > 0) ++ if (arg_check_inhibitors == 0 || arg_force > 0) + return 0; + + if (arg_when > 0) + return 0; + +- if (geteuid() == 0) +- return 0; ++ if (arg_check_inhibitors < 0) { ++ if (geteuid() == 0) ++ return 0; + +- if (!on_tty()) +- return 0; ++ if (!on_tty()) ++ return 0; ++ } + + if (arg_transport != BUS_TRANSPORT_LOCAL) + return 0; +@@ -7237,8 +7239,10 @@ static void systemctl_help(void) { + " When enqueuing a unit job, show full transaction\n" + " --show-types When showing sockets, explicitly show their type\n" + " --value When showing properties, only print the value\n" +- " -i --ignore-inhibitors\n" +- " When shutting down or sleeping, ignore inhibitors\n" ++ " --check-inhibitors=MODE\n" ++ " Specify if checking inhibitors before shutting down,\n" ++ " sleeping or hibernating\n" ++ " -i Shortcut for --check-inhibitors=no\n" + " --kill-who=WHO Who to send signal to\n" + " -s --signal=SIGNAL Which signal to send\n" + " --now Start or stop unit in addition to enabling or disabling it\n" +@@ -7475,6 +7479,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { + ARG_REVERSE, + ARG_AFTER, + ARG_BEFORE, ++ ARG_CHECK_INHIBITORS, + ARG_DRY_RUN, + ARG_SHOW_TYPES, + ARG_IRREVERSIBLE, +@@ -7520,7 +7525,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { + { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */ + { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */ + { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */ +- { "ignore-inhibitors", no_argument, NULL, 'i' }, ++ { "ignore-inhibitors", no_argument, NULL, 'i' }, /* compatibility only */ ++ { "check-inhibitors", required_argument, NULL, ARG_CHECK_INHIBITORS }, + { "value", no_argument, NULL, ARG_VALUE }, + { "user", no_argument, NULL, ARG_USER }, + { "system", no_argument, NULL, ARG_SYSTEM }, +@@ -7813,7 +7819,18 @@ static int systemctl_parse_argv(int argc, char *argv[]) { + break; + + case 'i': +- arg_ignore_inhibitors = true; ++ arg_check_inhibitors = 0; ++ break; ++ ++ case ARG_CHECK_INHIBITORS: ++ if (streq(optarg, "auto")) ++ arg_check_inhibitors = -1; ++ else { ++ r = parse_boolean(optarg); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse --check-inhibitors= argument: %s", optarg); ++ arg_check_inhibitors = r; ++ } + break; + + case ARG_PLAIN: diff --git a/SOURCES/0612-logind-Introduce-RebootWithFlags-and-others.patch b/SOURCES/0612-logind-Introduce-RebootWithFlags-and-others.patch new file mode 100644 index 0000000..fc9c119 --- /dev/null +++ b/SOURCES/0612-logind-Introduce-RebootWithFlags-and-others.patch @@ -0,0 +1,769 @@ +From d375206fe822903b16f3b9006ea47ffd938d88cb Mon Sep 17 00:00:00 2001 +From: Deepak Rawat +Date: Mon, 25 Jan 2021 09:14:08 -0800 +Subject: [PATCH] logind: Introduce RebootWithFlags and others + +Add new systemd-logind WithFlags version for Reboot and others. These +methods add a unit64 parameter, with which can send additional control flags. + +(cherry picked from commit 00971ea5164e2e7a5f2d7ffe12a566b62d282556) + +Related: #1269726 +--- + src/basic/login-util.h | 8 + + src/login/logind-dbus.c | 498 +++++++++++++++++++++++++++++++----- + src/systemctl/systemctl.c | 26 ++ + src/systemd/sd-bus-vtable.h | 19 +- + 4 files changed, 480 insertions(+), 71 deletions(-) + +diff --git a/src/basic/login-util.h b/src/basic/login-util.h +index e1e62e12b7..9832207458 100644 +--- a/src/basic/login-util.h ++++ b/src/basic/login-util.h +@@ -4,6 +4,14 @@ + #include + #include + ++#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) ++ ++/* For internal use only */ ++#define SD_LOGIND_INTERACTIVE (UINT64_C(1) << 63) ++ ++#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS) ++#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_INTERACTIVE) ++ + bool session_id_valid(const char *id); + + static inline bool logind_running(void) { +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 3f122fcbd9..0c43fbb3e0 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -1698,14 +1698,14 @@ static int verify_shutdown_creds( + Manager *m, + sd_bus_message *message, + InhibitWhat w, +- bool interactive, + const char *action, + const char *action_multiple_sessions, + const char *action_ignore_inhibit, ++ uint64_t flags, + sd_bus_error *error) { + + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; +- bool multiple_sessions, blocked; ++ bool multiple_sessions, blocked, interactive; + uid_t uid; + int r; + +@@ -1728,6 +1728,7 @@ static int verify_shutdown_creds( + + multiple_sessions = r > 0; + blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); ++ interactive = flags & SD_LOGIND_INTERACTIVE; + + if (multiple_sessions && action_multiple_sessions) { + r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error); +@@ -1737,12 +1738,19 @@ static int verify_shutdown_creds( + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + } + +- if (blocked && action_ignore_inhibit) { +- r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error); +- if (r < 0) +- return r; +- if (r == 0) +- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ ++ if (blocked) { ++ /* We don't check polkit for root here, because you can't be more privileged than root */ ++ if (uid == 0 && (flags & SD_LOGIND_ROOT_CHECK_INHIBITORS)) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, ++ "Access denied to root due to active block inhibitor"); ++ ++ if (action_ignore_inhibit) { ++ r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ ++ } + } + + if (!multiple_sessions && !blocked && action) { +@@ -1765,9 +1773,11 @@ static int method_do_shutdown_or_sleep( + const char *action_multiple_sessions, + const char *action_ignore_inhibit, + const char *sleep_verb, ++ bool with_flags, + sd_bus_error *error) { + +- int interactive, r; ++ int interactive = false, r; ++ uint64_t flags = 0; + + assert(m); + assert(message); +@@ -1775,10 +1785,20 @@ static int method_do_shutdown_or_sleep( + assert(w >= 0); + assert(w <= _INHIBIT_WHAT_MAX); + +- r = sd_bus_message_read(message, "b", &interactive); ++ if (with_flags) ++ r = sd_bus_message_read(message, "t", &flags); ++ else ++ r = sd_bus_message_read(message, "b", &interactive); ++ + if (r < 0) + return r; + ++ if (with_flags && (flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC)) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, ++ "Invalid flags parameter"); ++ ++ SET_FLAG(flags, SD_LOGIND_INTERACTIVE, interactive); ++ + /* Don't allow multiple jobs being executed at the same time */ + if (m->action_what) + return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress"); +@@ -1795,8 +1815,8 @@ static int method_do_shutdown_or_sleep( + return r; + } + +- r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions, +- action_ignore_inhibit, error); ++ r = verify_shutdown_creds(m, message, w, action, action_multiple_sessions, ++ action_ignore_inhibit, flags, error); + if (r != 0) + return r; + +@@ -1818,6 +1838,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error + "org.freedesktop.login1.power-off-multiple-sessions", + "org.freedesktop.login1.power-off-ignore-inhibit", + NULL, ++ sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"), + error); + } + +@@ -1832,6 +1853,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * + "org.freedesktop.login1.reboot-multiple-sessions", + "org.freedesktop.login1.reboot-ignore-inhibit", + NULL, ++ sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"), + error); + } + +@@ -1846,6 +1868,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er + "org.freedesktop.login1.halt-multiple-sessions", + "org.freedesktop.login1.halt-ignore-inhibit", + NULL, ++ sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"), + error); + } + +@@ -1860,6 +1883,7 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error + "org.freedesktop.login1.suspend-multiple-sessions", + "org.freedesktop.login1.suspend-ignore-inhibit", + "suspend", ++ sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"), + error); + } + +@@ -1874,6 +1898,7 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hibernate", ++ sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"), + error); + } + +@@ -1888,6 +1913,7 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hybrid-sleep", ++ sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"), + error); + } + +@@ -1902,6 +1928,7 @@ static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hybrid-sleep", ++ sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"), + error); + } + +@@ -2089,8 +2116,8 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ + } else + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); + +- r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, false, +- action, action_multiple_sessions, action_ignore_inhibit, error); ++ r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, action, action_multiple_sessions, ++ action_ignore_inhibit, 0, error); + if (r != 0) + return r; + +@@ -2683,60 +2710,395 @@ const sd_bus_vtable manager_vtable[] = { + SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_hashmap_size, offsetof(Manager, sessions), 0), + SD_BUS_PROPERTY("UserTasksMax", "t", property_get_compat_user_tasks_max, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + +- SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("GetUser", "u", "o", method_get_user, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("GetUserByPID", "u", "o", method_get_user_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("GetSeat", "s", "o", method_get_seat, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("ListSessions", NULL, "a(susso)", method_list_sessions, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("ListUsers", NULL, "a(uso)", method_list_users, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("ListSeats", NULL, "a(so)", method_list_seats, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("ListInhibitors", NULL, "a(ssssuu)", method_list_inhibitors, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CreateSession", "uusssssussbssa(sv)", "soshusub", method_create_session, 0), +- SD_BUS_METHOD("ReleaseSession", "s", NULL, method_release_session, 0), +- SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("LockSession", "s", NULL, method_lock_session, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("UnlockSession", "s", NULL, method_lock_session, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("LockSessions", NULL, NULL, method_lock_sessions, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("UnlockSessions", NULL, NULL, method_lock_sessions, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("KillSession", "ssi", NULL, method_kill_session, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("KillUser", "ui", NULL, method_kill_user, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("SetUserLinger", "ubb", NULL, method_set_user_linger, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("AttachDevice", "ssb", NULL, method_attach_device, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("Halt", "b", NULL, method_halt, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("SuspendThenHibernate", "b", NULL, method_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CanHalt", NULL, "s", method_can_halt, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CanSuspendThenHibernate", NULL, "s", method_can_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("SetWallMessage", "sb", NULL, method_set_wall_message, SD_BUS_VTABLE_UNPRIVILEGED), +- +- SD_BUS_SIGNAL("SessionNew", "so", 0), +- SD_BUS_SIGNAL("SessionRemoved", "so", 0), +- SD_BUS_SIGNAL("UserNew", "uo", 0), +- SD_BUS_SIGNAL("UserRemoved", "uo", 0), +- SD_BUS_SIGNAL("SeatNew", "so", 0), +- SD_BUS_SIGNAL("SeatRemoved", "so", 0), +- SD_BUS_SIGNAL("PrepareForShutdown", "b", 0), +- SD_BUS_SIGNAL("PrepareForSleep", "b", 0), ++ SD_BUS_METHOD_WITH_NAMES("GetSession", ++ "s", ++ SD_BUS_PARAM(session_id), ++ "o", ++ SD_BUS_PARAM(object_path), ++ method_get_session, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("GetSessionByPID", ++ "u", ++ SD_BUS_PARAM(pid), ++ "o", ++ SD_BUS_PARAM(object_path), ++ method_get_session_by_pid, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("GetUser", ++ "u", ++ SD_BUS_PARAM(uid), ++ "o", ++ SD_BUS_PARAM(object_path), ++ method_get_user, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("GetUserByPID", ++ "u", ++ SD_BUS_PARAM(pid), ++ "o", ++ SD_BUS_PARAM(object_path), ++ method_get_user_by_pid, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("GetSeat", ++ "s", ++ SD_BUS_PARAM(seat_id), ++ "o", ++ SD_BUS_PARAM(object_path), ++ method_get_seat, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("ListSessions", ++ NULL,, ++ "a(susso)", ++ SD_BUS_PARAM(sessions), ++ method_list_sessions, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("ListUsers", ++ NULL,, ++ "a(uso)", ++ SD_BUS_PARAM(users), ++ method_list_users, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("ListSeats", ++ NULL,, ++ "a(so)", ++ SD_BUS_PARAM(seats), ++ method_list_seats, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("ListInhibitors", ++ NULL,, ++ "a(ssssuu)", ++ SD_BUS_PARAM(inhibitors), ++ method_list_inhibitors, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CreateSession", ++ "uusssssussbssa(sv)", ++ SD_BUS_PARAM(uid) ++ SD_BUS_PARAM(pid) ++ SD_BUS_PARAM(service) ++ SD_BUS_PARAM(type) ++ SD_BUS_PARAM(class) ++ SD_BUS_PARAM(desktop) ++ SD_BUS_PARAM(seat_id) ++ SD_BUS_PARAM(vtnr) ++ SD_BUS_PARAM(tty) ++ SD_BUS_PARAM(display) ++ SD_BUS_PARAM(remote) ++ SD_BUS_PARAM(remote_user) ++ SD_BUS_PARAM(remote_host) ++ SD_BUS_PARAM(properties), ++ "soshusub", ++ SD_BUS_PARAM(session_id) ++ SD_BUS_PARAM(object_path) ++ SD_BUS_PARAM(runtime_path) ++ SD_BUS_PARAM(fifo_fd) ++ SD_BUS_PARAM(uid) ++ SD_BUS_PARAM(seat_id) ++ SD_BUS_PARAM(vtnr) ++ SD_BUS_PARAM(existing), ++ method_create_session, ++ 0), ++ SD_BUS_METHOD_WITH_NAMES("ReleaseSession", ++ "s", ++ SD_BUS_PARAM(session_id), ++ NULL,, ++ method_release_session, ++ 0), ++ SD_BUS_METHOD_WITH_NAMES("ActivateSession", ++ "s", ++ SD_BUS_PARAM(session_id), ++ NULL,, ++ method_activate_session, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("ActivateSessionOnSeat", ++ "ss", ++ SD_BUS_PARAM(session_id) ++ SD_BUS_PARAM(seat_id), ++ NULL,, ++ method_activate_session_on_seat, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("LockSession", ++ "s", ++ SD_BUS_PARAM(session_id), ++ NULL,, ++ method_lock_session, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("UnlockSession", ++ "s", ++ SD_BUS_PARAM(session_id), ++ NULL,, ++ method_lock_session, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("LockSessions", ++ NULL, ++ NULL, ++ method_lock_sessions, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD("UnlockSessions", ++ NULL, ++ NULL, ++ method_lock_sessions, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("KillSession", ++ "ssi", ++ SD_BUS_PARAM(session_id) ++ SD_BUS_PARAM(who) ++ SD_BUS_PARAM(signal_number), ++ NULL,, ++ method_kill_session, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("KillUser", ++ "ui", ++ SD_BUS_PARAM(uid) ++ SD_BUS_PARAM(signal_number), ++ NULL,, ++ method_kill_user, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("TerminateSession", ++ "s", ++ SD_BUS_PARAM(session_id), ++ NULL,, ++ method_terminate_session, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("TerminateUser", ++ "u", ++ SD_BUS_PARAM(uid), ++ NULL,, ++ method_terminate_user, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("TerminateSeat", ++ "s", ++ SD_BUS_PARAM(seat_id), ++ NULL,, ++ method_terminate_seat, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("SetUserLinger", ++ "ubb", ++ SD_BUS_PARAM(uid) ++ SD_BUS_PARAM(enable) ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_set_user_linger, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("AttachDevice", ++ "ssb", ++ SD_BUS_PARAM(seat_id) ++ SD_BUS_PARAM(sysfs_path) ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_attach_device, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("FlushDevices", ++ "b", ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_flush_devices, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("PowerOff", ++ "b", ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_poweroff, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("PowerOffWithFlags", ++ "t", ++ SD_BUS_PARAM(flags), ++ NULL,, ++ method_poweroff, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("Reboot", ++ "b", ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_reboot, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("RebootWithFlags", ++ "t", ++ SD_BUS_PARAM(flags), ++ NULL,, ++ method_reboot, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("Halt", ++ "b", ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_halt, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("HaltWithFlags", ++ "t", ++ SD_BUS_PARAM(flags), ++ NULL,, ++ method_halt, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("Suspend", ++ "b", ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_suspend, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("SuspendWithFlags", ++ "t", ++ SD_BUS_PARAM(flags), ++ NULL,, ++ method_suspend, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("Hibernate", ++ "b", ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_hibernate, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("HibernateWithFlags", ++ "t", ++ SD_BUS_PARAM(flags), ++ NULL,, ++ method_hibernate, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("HybridSleep", ++ "b", ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_hybrid_sleep, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("HybridSleepWithFlags", ++ "t", ++ SD_BUS_PARAM(flags), ++ NULL,, ++ method_hybrid_sleep, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("SuspendThenHibernate", ++ "b", ++ SD_BUS_PARAM(interactive), ++ NULL,, ++ method_suspend_then_hibernate, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("SuspendThenHibernateWithFlags", ++ "t", ++ SD_BUS_PARAM(flags), ++ NULL,, ++ method_suspend_then_hibernate, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CanPowerOff", ++ NULL,, ++ "s", ++ SD_BUS_PARAM(result), ++ method_can_poweroff, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CanReboot", ++ NULL,, ++ "s", ++ SD_BUS_PARAM(result), ++ method_can_reboot, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CanHalt", ++ NULL,, ++ "s", ++ SD_BUS_PARAM(result), ++ method_can_halt, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CanSuspend", ++ NULL,, ++ "s", ++ SD_BUS_PARAM(result), ++ method_can_suspend, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CanHibernate", ++ NULL,, ++ "s", ++ SD_BUS_PARAM(result), ++ method_can_hibernate, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CanHybridSleep", ++ NULL,, ++ "s", ++ SD_BUS_PARAM(result), ++ method_can_hybrid_sleep, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CanSuspendThenHibernate", ++ NULL,, ++ "s", ++ SD_BUS_PARAM(result), ++ method_can_suspend_then_hibernate, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("ScheduleShutdown", ++ "st", ++ SD_BUS_PARAM(type) ++ SD_BUS_PARAM(usec), ++ NULL,, ++ method_schedule_shutdown, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CancelScheduledShutdown", ++ NULL,, ++ "b", ++ SD_BUS_PARAM(cancelled), ++ method_cancel_scheduled_shutdown, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("Inhibit", ++ "ssss", ++ SD_BUS_PARAM(what) ++ SD_BUS_PARAM(who) ++ SD_BUS_PARAM(why) ++ SD_BUS_PARAM(mode), ++ "h", ++ SD_BUS_PARAM(pipe_fd), ++ method_inhibit, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("CanRebootToFirmwareSetup", ++ NULL,, ++ "s", ++ SD_BUS_PARAM(result), ++ method_can_reboot_to_firmware_setup, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("SetRebootToFirmwareSetup", ++ "b", ++ SD_BUS_PARAM(enable), ++ NULL,, ++ method_set_reboot_to_firmware_setup, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ SD_BUS_METHOD_WITH_NAMES("SetWallMessage", ++ "sb", ++ SD_BUS_PARAM(wall_message) ++ SD_BUS_PARAM(enable), ++ NULL,, ++ method_set_wall_message, ++ SD_BUS_VTABLE_UNPRIVILEGED), ++ ++ SD_BUS_SIGNAL_WITH_NAMES("SessionNew", ++ "so", ++ SD_BUS_PARAM(session_id) ++ SD_BUS_PARAM(object_path), ++ 0), ++ SD_BUS_SIGNAL_WITH_NAMES("SessionRemoved", ++ "so", ++ SD_BUS_PARAM(session_id) ++ SD_BUS_PARAM(object_path), ++ 0), ++ SD_BUS_SIGNAL_WITH_NAMES("UserNew", ++ "uo", ++ SD_BUS_PARAM(uid) ++ SD_BUS_PARAM(object_path), ++ 0), ++ SD_BUS_SIGNAL_WITH_NAMES("UserRemoved", ++ "uo", ++ SD_BUS_PARAM(uid) ++ SD_BUS_PARAM(object_path), ++ 0), ++ SD_BUS_SIGNAL_WITH_NAMES("SeatNew", ++ "so", ++ SD_BUS_PARAM(seat_id) ++ SD_BUS_PARAM(object_path), ++ 0), ++ SD_BUS_SIGNAL_WITH_NAMES("SeatRemoved", ++ "so", ++ SD_BUS_PARAM(seat_id) ++ SD_BUS_PARAM(object_path), ++ 0), ++ SD_BUS_SIGNAL_WITH_NAMES("PrepareForShutdown", ++ "b", ++ SD_BUS_PARAM(start), ++ 0), ++ SD_BUS_SIGNAL_WITH_NAMES("PrepareForSleep", ++ "b", ++ SD_BUS_PARAM(start), ++ 0), + + SD_BUS_VTABLE_END + }; +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 8bcbf6bf4b..3dd7c1522f 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -50,6 +50,7 @@ + #include "list.h" + #include "locale-util.h" + #include "log.h" ++#include "login-util.h" + #include "logs-show.h" + #include "macro.h" + #include "mkdir.h" +@@ -3266,6 +3267,8 @@ static int logind_reboot(enum action a) { + }; + + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; ++ const char *method_with_flags; ++ uint64_t flags = 0; + sd_bus *bus; + int r; + +@@ -3284,6 +3287,29 @@ static int logind_reboot(enum action a) { + if (arg_dry_run) + return 0; + ++ SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0); ++ ++ method_with_flags = strjoina(actions[a].method, "WithFlags"); ++ ++ r = sd_bus_call_method( ++ bus, ++ "org.freedesktop.login1", ++ "/org/freedesktop/login1", ++ "org.freedesktop.login1.Manager", ++ method_with_flags, ++ &error, ++ NULL, ++ "t", flags); ++ if (r >= 0) ++ return 0; ++ ++ if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) ++ return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r)); ++ ++ /* Fallback to original methods in case there is older version of systemd-logind */ ++ log_debug("Method %s not available: %s. Falling back to %s", method_with_flags, bus_error_message(&error, r), actions[a].method); ++ sd_bus_error_free(&error); ++ + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", +diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h +index 1268085498..8805e19477 100644 +--- a/src/systemd/sd-bus-vtable.h ++++ b/src/systemd/sd-bus-vtable.h +@@ -65,10 +65,12 @@ struct sd_bus_vtable { + const char *result; + sd_bus_message_handler_t handler; + size_t offset; ++ const char *names; + } method; + struct { + const char *member; + const char *signature; ++ const char *names; + } signal; + struct { + const char *member; +@@ -91,7 +93,10 @@ struct sd_bus_vtable { + }, \ + } + +-#define SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, _offset, _flags) \ ++/* helper macro to format method and signal parameters, one at a time */ ++#define SD_BUS_PARAM(x) #x "\0" ++ ++#define SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, _signature, _in_names, _result, _out_names, _handler, _offset, _flags) \ + { \ + .type = _SD_BUS_VTABLE_METHOD, \ + .flags = _flags, \ +@@ -102,13 +107,18 @@ struct sd_bus_vtable { + .result = _result, \ + .handler = _handler, \ + .offset = _offset, \ ++ .names = _in_names _out_names, \ + }, \ + }, \ + } ++#define SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, _offset, _flags) \ ++ SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, _signature, "", _result, "", _handler, _offset, _flags) ++#define SD_BUS_METHOD_WITH_NAMES(_member, _signature, _in_names, _result, _out_names, _handler, _flags) \ ++ SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, _signature, _in_names, _result, _out_names, _handler, 0, _flags) + #define SD_BUS_METHOD(_member, _signature, _result, _handler, _flags) \ +- SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, 0, _flags) ++ SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, _signature, "", _result, "", _handler, 0, _flags) + +-#define SD_BUS_SIGNAL(_member, _signature, _flags) \ ++#define SD_BUS_SIGNAL_WITH_NAMES(_member, _signature, _out_names, _flags) \ + { \ + .type = _SD_BUS_VTABLE_SIGNAL, \ + .flags = _flags, \ +@@ -116,9 +126,12 @@ struct sd_bus_vtable { + .signal = { \ + .member = _member, \ + .signature = _signature, \ ++ .names = _out_names, \ + }, \ + }, \ + } ++#define SD_BUS_SIGNAL(_member, _signature, _flags) \ ++ SD_BUS_SIGNAL_WITH_NAMES(_member, _signature, "", _flags) + + #define SD_BUS_PROPERTY(_member, _signature, _get, _offset, _flags) \ + { \ diff --git a/SOURCES/0613-logind-add-WithFlags-methods-to-policy.patch b/SOURCES/0613-logind-add-WithFlags-methods-to-policy.patch new file mode 100644 index 0000000..753c9d9 --- /dev/null +++ b/SOURCES/0613-logind-add-WithFlags-methods-to-policy.patch @@ -0,0 +1,85 @@ +From e1b18ab36b2457a4896e531f03713b198725c919 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 9 Mar 2021 09:03:58 +0100 +Subject: [PATCH] =?UTF-8?q?logind:=20add=20=E2=80=A6WithFlags=20methods=20?= + =?UTF-8?q?to=20policy?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Without this, privilege escalation through polkit does not work, because all +methods fail with permission errors. + +Forgotten in 8885fed4e3a52cf1bf105e42043203c485ed9d92. +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1933335. + +(cherry picked from commit 2280db756eaff795091871feee8e47d4f6989a58) + +Related: #1269726 +--- + src/login/org.freedesktop.login1.conf | 28 +++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf +index f880f3e2da..dcde0c22c6 100644 +--- a/src/login/org.freedesktop.login1.conf ++++ b/src/login/org.freedesktop.login1.conf +@@ -130,30 +130,58 @@ + send_interface="org.freedesktop.login1.Manager" + send_member="PowerOff"/> + ++ ++ + + ++ ++ + + ++ ++ + + ++ ++ + + ++ ++ + + ++ ++ + + ++ ++ + diff --git a/SOURCES/0614-logind-simplify-flags-handling-a-bit.patch b/SOURCES/0614-logind-simplify-flags-handling-a-bit.patch new file mode 100644 index 0000000..fb61d3c --- /dev/null +++ b/SOURCES/0614-logind-simplify-flags-handling-a-bit.patch @@ -0,0 +1,72 @@ +From 6751217a032dd1a8e8ee324332f29786265f0ebe Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 2 Feb 2021 15:27:30 +0100 +Subject: [PATCH] logind: simplify flags handling a bit + +Let's split out the two codepaths a bit, and emphasize which ones it the +new-style and which the old-style codepath, and let's clearly convert +the params of the old-stye into the new style for further processing, so +that the old style path is brief and isolated. + +No change in behaviour. + +Follow-up for: 8885fed4e3a52cf1bf105e42043203c485ed9d92 + +(cherry picked from commit d3e99bc0c7f785dcf4e73cfed12f74002e73be5f) + +Related: #1269726 +--- + src/login/logind-dbus.c | 30 ++++++++++++++++++------------ + 1 file changed, 18 insertions(+), 12 deletions(-) + +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 0c43fbb3e0..ae9abc9bce 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -1776,8 +1776,8 @@ static int method_do_shutdown_or_sleep( + bool with_flags, + sd_bus_error *error) { + +- int interactive = false, r; +- uint64_t flags = 0; ++ uint64_t flags; ++ int r; + + assert(m); + assert(message); +@@ -1785,19 +1785,25 @@ static int method_do_shutdown_or_sleep( + assert(w >= 0); + assert(w <= _INHIBIT_WHAT_MAX); + +- if (with_flags) ++ if (with_flags) { ++ /* New style method: with flags parameter (and interactive bool in the bus message header) */ + r = sd_bus_message_read(message, "t", &flags); +- else +- r = sd_bus_message_read(message, "b", &interactive); +- +- if (r < 0) +- return r; ++ if (r < 0) ++ return r; ++ if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter"); ++ } else { ++ /* Old style method: no flags parameter, but interactive bool passed as boolean in ++ * payload. Let's convert this argument to the new-style flags parameter for our internal ++ * use. */ ++ int interactive; + +- if (with_flags && (flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, +- "Invalid flags parameter"); ++ r = sd_bus_message_read(message, "b", &interactive); ++ if (r < 0) ++ return r; + +- SET_FLAG(flags, SD_LOGIND_INTERACTIVE, interactive); ++ flags = interactive ? SD_LOGIND_INTERACTIVE : 0; ++ } + + /* Don't allow multiple jobs being executed at the same time */ + if (m->action_what) diff --git a/SOURCES/0615-Update-link-to-RHEL-documentation.patch b/SOURCES/0615-Update-link-to-RHEL-documentation.patch new file mode 100644 index 0000000..922b826 --- /dev/null +++ b/SOURCES/0615-Update-link-to-RHEL-documentation.patch @@ -0,0 +1,25 @@ +From 48b893c770aed3214586d529ddaba14267818c33 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Thu, 15 Jul 2021 10:35:08 +0200 +Subject: [PATCH] Update link to RHEL documentation + +RHEL-only + +Resolves: #1982584 +--- + man/systemctl.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 9f0f4d46ea..a71e6c7c4f 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -2017,7 +2017,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err + + For examples how to use systemctl in comparsion + with old service and chkconfig command please see: +- ++ + Managing System Services + + diff --git a/SOURCES/0616-Set-default-core-ulimit-to-0-but-keep-the-hard-limit.patch b/SOURCES/0616-Set-default-core-ulimit-to-0-but-keep-the-hard-limit.patch new file mode 100644 index 0000000..a1893a2 --- /dev/null +++ b/SOURCES/0616-Set-default-core-ulimit-to-0-but-keep-the-hard-limit.patch @@ -0,0 +1,29 @@ +From e2f5e8ccb27f48717b50339f58582d70ad5f59b1 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Tue, 3 Aug 2021 11:52:36 +0200 +Subject: [PATCH] Set default core ulimit to 0, but keep the hard limit + ulimited + +so users can change it later. + +Follow-up to 830bd662276ee117e65a4b3d541f77e8b172eafd. + +rhel-only +Resolves: #1905582 +--- + src/core/system.conf.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index b4d6dfa15a..84246c0e36 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -52,7 +52,7 @@ + #DefaultLimitFSIZE= + #DefaultLimitDATA= + #DefaultLimitSTACK= +-DefaultLimitCORE=0 ++DefaultLimitCORE=0:infinity + #DefaultLimitRSS= + #DefaultLimitNOFILE= + #DefaultLimitAS= diff --git a/SOURCES/0617-shared-seccomp-util-address-family-filtering-is-brok.patch b/SOURCES/0617-shared-seccomp-util-address-family-filtering-is-brok.patch new file mode 100644 index 0000000..f3f13ad --- /dev/null +++ b/SOURCES/0617-shared-seccomp-util-address-family-filtering-is-brok.patch @@ -0,0 +1,76 @@ +From 3cf73fa4599116da350a0100378e749bbcbcad37 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 26 Nov 2020 11:23:54 +0100 +Subject: [PATCH] shared/seccomp-util: address family filtering is broken on + ppc + +This reverts the gist of da1921a5c396547261c8c7fcd94173346eb3b718 and +0d9fca76bb69e162265b2d25cb79f1890c0da31b (for ppc). + +Quoting #17559: +> libseccomp 2.5 added socket syscall multiplexing on ppc64(el): +> https://github.com/seccomp/libseccomp/pull/229 +> +> Like with i386, s390 and s390x this breaks socket argument filtering, so +> RestrictAddressFamilies doesn't work. +> +> This causes the unit test to fail: +> /* test_restrict_address_families */ +> Operating on architecture: ppc +> Failed to install socket family rules for architecture ppc, skipping: Operation canceled +> Operating on architecture: ppc64 +> Failed to add socket() rule for architecture ppc64, skipping: Invalid argument +> Operating on architecture: ppc64-le +> Failed to add socket() rule for architecture ppc64-le, skipping: Invalid argument +> Assertion 'fd < 0' failed at src/test/test-seccomp.c:424, function test_restrict_address_families(). Aborting. +> +> The socket filters can't be added so `socket(AF_UNIX, SOCK_DGRAM, 0);` still +> works, triggering the assertion. + +Fixes #17559. + +(cherry picked from commit d5923e38bc0e6cf9d7620ed5f1f8606fe7fe1168) + +Resolves: #1982650 +--- + src/shared/seccomp-util.c | 6 +++--- + src/test/test-seccomp.c | 2 +- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c +index e903512d45..c57c409433 100644 +--- a/src/shared/seccomp-util.c ++++ b/src/shared/seccomp-util.c +@@ -1251,9 +1251,6 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) { + case SCMP_ARCH_X32: + case SCMP_ARCH_ARM: + case SCMP_ARCH_AARCH64: +- case SCMP_ARCH_PPC: +- case SCMP_ARCH_PPC64: +- case SCMP_ARCH_PPC64LE: + case SCMP_ARCH_MIPSEL64N32: + case SCMP_ARCH_MIPS64N32: + case SCMP_ARCH_MIPSEL64: +@@ -1267,6 +1264,9 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) { + case SCMP_ARCH_X86: + case SCMP_ARCH_MIPSEL: + case SCMP_ARCH_MIPS: ++ case SCMP_ARCH_PPC: ++ case SCMP_ARCH_PPC64: ++ case SCMP_ARCH_PPC64LE: + default: + /* These we either know we don't support (i.e. are the ones that do use socketcall()), or we + * don't know */ +diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c +index 009a2e1922..5eb1c78b8b 100644 +--- a/src/test/test-seccomp.c ++++ b/src/test/test-seccomp.c +@@ -25,7 +25,7 @@ + #include "util.h" + #include "virt.h" + +-#if SCMP_SYS(socket) < 0 || defined(__i386__) || defined(__s390x__) || defined(__s390__) ++#if SCMP_SYS(socket) < 0 || defined(__i386__) || defined(__s390x__) || defined(__s390__) || defined(__powerpc64__) || defined(__powerpc__) + /* On these archs, socket() is implemented via the socketcall() syscall multiplexer, + * and we can't restrict it hence via seccomp. */ + # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 1 diff --git a/SOURCES/0618-logind-rework-Seat-Session-User-object-allocation-an.patch b/SOURCES/0618-logind-rework-Seat-Session-User-object-allocation-an.patch new file mode 100644 index 0000000..bddc651 --- /dev/null +++ b/SOURCES/0618-logind-rework-Seat-Session-User-object-allocation-an.patch @@ -0,0 +1,341 @@ +From 019b3a5d7530c51aa8f7f1e5f5cb5eb81113d4db Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Aug 2018 18:53:09 +0200 +Subject: [PATCH] logind: rework Seat/Session/User object allocation and + freeing a bit + +Let's update things a bit to follow current practices: + +- User structure initialization rather than zero-initialized allocation + +- Always propagate proper errors from allocation functions + +- Use _cleanup_ for freeing objects when allocation fails half-way + +- Make destructors return NULL + +(cherry picked from commit 8c29a4570993105fecc12288596d2ee77c7f82b8) + +Related: #1642460 +--- + src/login/logind-core.c | 14 ++++++---- + src/login/logind-seat.c | 38 +++++++++++++++---------- + src/login/logind-seat.h | 6 ++-- + src/login/logind-session.c | 57 +++++++++++++++++++++----------------- + src/login/logind-session.h | 7 +++-- + src/login/logind-user.c | 21 +++++++------- + 6 files changed, 83 insertions(+), 60 deletions(-) + +diff --git a/src/login/logind-core.c b/src/login/logind-core.c +index cff5536ac0..f598bbaa1c 100644 +--- a/src/login/logind-core.c ++++ b/src/login/logind-core.c +@@ -88,15 +88,16 @@ int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_dev + + int manager_add_seat(Manager *m, const char *id, Seat **_seat) { + Seat *s; ++ int r; + + assert(m); + assert(id); + + s = hashmap_get(m->seats, id); + if (!s) { +- s = seat_new(m, id); +- if (!s) +- return -ENOMEM; ++ r = seat_new(&s, m, id); ++ if (r < 0) ++ return r; + } + + if (_seat) +@@ -107,15 +108,16 @@ int manager_add_seat(Manager *m, const char *id, Seat **_seat) { + + int manager_add_session(Manager *m, const char *id, Session **_session) { + Session *s; ++ int r; + + assert(m); + assert(id); + + s = hashmap_get(m->sessions, id); + if (!s) { +- s = session_new(m, id); +- if (!s) +- return -ENOMEM; ++ r = session_new(&s, m, id); ++ if (r < 0) ++ return r; + } + + if (_session) +diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c +index 63253db5bf..f68fc0ceaa 100644 +--- a/src/login/logind-seat.c ++++ b/src/login/logind-seat.c +@@ -21,33 +21,42 @@ + #include "terminal-util.h" + #include "util.h" + +-Seat *seat_new(Manager *m, const char *id) { +- Seat *s; ++int seat_new(Seat** ret, Manager *m, const char *id) { ++ _cleanup_(seat_freep) Seat *s = NULL; ++ int r; + ++ assert(ret); + assert(m); + assert(id); + +- s = new0(Seat, 1); ++ if (!seat_name_is_valid(id)) ++ return -EINVAL; ++ ++ s = new(Seat, 1); + if (!s) +- return NULL; ++ return -ENOMEM; ++ ++ *s = (Seat) { ++ .manager = m, ++ }; + + s->state_file = strappend("/run/systemd/seats/", id); + if (!s->state_file) +- return mfree(s); ++ return -ENOMEM; + + s->id = basename(s->state_file); +- s->manager = m; + +- if (hashmap_put(m->seats, s->id, s) < 0) { +- free(s->state_file); +- return mfree(s); +- } ++ r = hashmap_put(m->seats, s->id, s); ++ if (r < 0) ++ return r; + +- return s; ++ *ret = TAKE_PTR(s); ++ return 0; + } + +-void seat_free(Seat *s) { +- assert(s); ++Seat* seat_free(Seat *s) { ++ if (!s) ++ return NULL; + + if (s->in_gc_queue) + LIST_REMOVE(gc_queue, s->manager->seat_gc_queue, s); +@@ -64,7 +73,8 @@ void seat_free(Seat *s) { + + free(s->positions); + free(s->state_file); +- free(s); ++ ++ return mfree(s); + } + + int seat_save(Seat *s) { +diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h +index 70878bbe52..51cd468e26 100644 +--- a/src/login/logind-seat.h ++++ b/src/login/logind-seat.h +@@ -27,8 +27,10 @@ struct Seat { + LIST_FIELDS(Seat, gc_queue); + }; + +-Seat *seat_new(Manager *m, const char *id); +-void seat_free(Seat *s); ++int seat_new(Seat **ret, Manager *m, const char *id); ++Seat* seat_free(Seat *s); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Seat *, seat_free); + + int seat_save(Seat *s); + int seat_load(Seat *s); +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 69d5a10319..5621d59a41 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -24,57 +24,61 @@ + #include "mkdir.h" + #include "parse-util.h" + #include "path-util.h" ++#include "process-util.h" + #include "string-table.h" + #include "terminal-util.h" + #include "user-util.h" + #include "util.h" +-#include "process-util.h" + + #define RELEASE_USEC (20*USEC_PER_SEC) + + static void session_remove_fifo(Session *s); + +-Session* session_new(Manager *m, const char *id) { +- Session *s; ++int session_new(Session **ret, Manager *m, const char *id) { ++ _cleanup_(session_freep) Session *s = NULL; ++ int r; + ++ assert(ret); + assert(m); + assert(id); +- assert(session_id_valid(id)); + +- s = new0(Session, 1); ++ if (!session_id_valid(id)) ++ return -EINVAL; ++ ++ s = new(Session, 1); + if (!s) +- return NULL; ++ return -ENOMEM; ++ ++ *s = (Session) { ++ .manager = m, ++ .fifo_fd = -1, ++ .vtfd = -1, ++ .audit_id = AUDIT_SESSION_INVALID, ++ }; + + s->state_file = strappend("/run/systemd/sessions/", id); + if (!s->state_file) +- return mfree(s); +- +- s->devices = hashmap_new(&devt_hash_ops); +- if (!s->devices) { +- free(s->state_file); +- return mfree(s); +- } ++ return -ENOMEM; + + s->id = basename(s->state_file); + +- if (hashmap_put(m->sessions, s->id, s) < 0) { +- hashmap_free(s->devices); +- free(s->state_file); +- return mfree(s); +- } ++ s->devices = hashmap_new(&devt_hash_ops); ++ if (!s->devices) ++ return -ENOMEM; + +- s->manager = m; +- s->fifo_fd = -1; +- s->vtfd = -1; +- s->audit_id = AUDIT_SESSION_INVALID; ++ r = hashmap_put(m->sessions, s->id, s); ++ if (r < 0) ++ return r; + +- return s; ++ *ret = TAKE_PTR(s); ++ return 0; + } + +-void session_free(Session *s) { ++Session* session_free(Session *s) { + SessionDevice *sd; + +- assert(s); ++ if (!s) ++ return NULL; + + if (s->in_gc_queue) + LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s); +@@ -126,7 +130,8 @@ void session_free(Session *s) { + hashmap_remove(s->manager->sessions, s->id); + + free(s->state_file); +- free(s); ++ ++ return mfree(s); + } + + void session_set_user(Session *s, User *u) { +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index 29ca399daf..572f2545c1 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -109,8 +109,11 @@ struct Session { + LIST_FIELDS(Session, gc_queue); + }; + +-Session *session_new(Manager *m, const char *id); +-void session_free(Session *s); ++int session_new(Session **ret, Manager *m, const char *id); ++Session* session_free(Session *s); ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(Session *, session_free); ++ + void session_set_user(Session *s, User *u); + bool session_may_gc(Session *s, bool drop_not_started); + void session_add_to_gc_queue(Session *s); +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 56b8066f12..60ccd62abb 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -30,23 +30,24 @@ + #include "user-util.h" + #include "util.h" + +-int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name) { ++int user_new(User **ret, Manager *m, uid_t uid, gid_t gid, const char *name) { + _cleanup_(user_freep) User *u = NULL; + char lu[DECIMAL_STR_MAX(uid_t) + 1]; + int r; + +- assert(out); ++ assert(ret); + assert(m); + assert(name); + +- u = new0(User, 1); ++ u = new(User, 1); + if (!u) + return -ENOMEM; + +- u->manager = m; +- u->uid = uid; +- u->gid = gid; +- xsprintf(lu, UID_FMT, uid); ++ *u = (User) { ++ .manager = m, ++ .uid = uid, ++ .gid = gid, ++ }; + + u->name = strdup(name); + if (!u->name) +@@ -58,6 +59,7 @@ int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name) { + if (asprintf(&u->runtime_path, "/run/user/"UID_FMT, uid) < 0) + return -ENOMEM; + ++ xsprintf(lu, UID_FMT, uid); + r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &u->slice); + if (r < 0) + return r; +@@ -78,8 +80,7 @@ int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name) { + if (r < 0) + return r; + +- *out = TAKE_PTR(u); +- ++ *ret = TAKE_PTR(u); + return 0; + } + +@@ -272,7 +273,7 @@ int user_save(User *u) { + if (!u->started) + return 0; + +- return user_save_internal (u); ++ return user_save_internal(u); + } + + int user_load(User *u) { diff --git a/SOURCES/0619-logind-fix-serialization-deserialization-of-user-s-d.patch b/SOURCES/0619-logind-fix-serialization-deserialization-of-user-s-d.patch new file mode 100644 index 0000000..7639b30 --- /dev/null +++ b/SOURCES/0619-logind-fix-serialization-deserialization-of-user-s-d.patch @@ -0,0 +1,116 @@ +From 0314e68fe961cec941b1b0eb1cbcca4546cfdfdb Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Aug 2018 19:04:35 +0200 +Subject: [PATCH] logind: fix serialization/deserialization of user's "display + session" + +Previously this was serialized as part of the user object. This didn't +work however, as we load users first, and sessions seconds and hence +referencing a session from the user load logic cannot work. + +Fix this by storing an IS_DISPLAY property along with each session, and +make the session with this set display session when it is loaded. + +(cherry picked from commit 1c8280fd47b6561d35b15b3b6d49bdeacf891bfd) + +Related: #1642460 +--- + src/login/logind-session.c | 18 +++++++++++++++++- + src/login/logind-user.c | 18 ++++-------------- + 2 files changed, 21 insertions(+), 15 deletions(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 5621d59a41..0afb065b2b 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -184,11 +184,13 @@ int session_save(Session *s) { + "UID="UID_FMT"\n" + "USER=%s\n" + "ACTIVE=%i\n" ++ "IS_DISPLAY=%i\n" + "STATE=%s\n" + "REMOTE=%i\n", + s->user->uid, + s->user->name, + session_is_active(s), ++ s->user->display == s, + session_state_to_string(session_get_state(s)), + s->remote); + +@@ -359,7 +361,8 @@ int session_load(Session *s) { + *monotonic = NULL, + *controller = NULL, + *active = NULL, +- *devices = NULL; ++ *devices = NULL, ++ *is_display = NULL; + + int k, r; + +@@ -389,6 +392,7 @@ int session_load(Session *s) { + "CONTROLLER", &controller, + "ACTIVE", &active, + "DEVICES", &devices, ++ "IS_DISPLAY", &is_display, + NULL); + + if (r < 0) +@@ -496,6 +500,18 @@ int session_load(Session *s) { + s->was_active = k; + } + ++ if (is_display) { ++ /* Note that when enumerating users are loaded before sessions, hence the display session to use is ++ * something we have to store along with the session and not the user, as in that case we couldn't ++ * apply it at the time we load the user. */ ++ ++ k = parse_boolean(is_display); ++ if (k < 0) ++ log_warning_errno(k, "Failed to parse IS_DISPLAY session property: %m"); ++ else if (k > 0) ++ s->user->display = s; ++ } ++ + if (controller) { + if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0) { + session_set_controller(s, controller, false, false); +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 60ccd62abb..17ed361411 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -277,8 +277,7 @@ int user_save(User *u) { + } + + int user_load(User *u) { +- _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL; +- Session *s = NULL; ++ _cleanup_free_ char *realtime = NULL, *monotonic = NULL; + int r; + + assert(u); +@@ -286,22 +285,13 @@ int user_load(User *u) { + r = parse_env_file(NULL, u->state_file, NEWLINE, + "SERVICE_JOB", &u->service_job, + "SLICE_JOB", &u->slice_job, +- "DISPLAY", &display, + "REALTIME", &realtime, + "MONOTONIC", &monotonic, + NULL); +- if (r < 0) { +- if (r == -ENOENT) +- return 0; +- ++ if (r == -ENOENT) ++ return 0; ++ if (r < 0) + return log_error_errno(r, "Failed to read %s: %m", u->state_file); +- } +- +- if (display) +- s = hashmap_get(u->manager->sessions, display); +- +- if (s && s->display && display_is_local(s->display)) +- u->display = s; + + if (realtime) + timestamp_deserialize(realtime, &u->timestamp.realtime); diff --git a/SOURCES/0620-logind-turn-of-stdio-locking-when-writing-session-fi.patch b/SOURCES/0620-logind-turn-of-stdio-locking-when-writing-session-fi.patch new file mode 100644 index 0000000..93c7244 --- /dev/null +++ b/SOURCES/0620-logind-turn-of-stdio-locking-when-writing-session-fi.patch @@ -0,0 +1,39 @@ +From 3eab0f1b64477792bd01ca52c3eb26ce64c5c7ba Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Aug 2018 20:18:55 +0200 +Subject: [PATCH] logind: turn of stdio locking when writing session files too + +This just copies what we already do for user and seat files to session +files. + +(cherry picked from commit 44176400138e18d9087e0864ca97041416a90d47) + +Related: #1642460 +--- + src/login/logind-session.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 0afb065b2b..960a24d1a7 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -175,9 +176,8 @@ int session_save(Session *s) { + if (r < 0) + goto fail; + +- assert(s->user); +- +- fchmod(fileno(f), 0644); ++ (void) __fsetlocking(f, FSETLOCKING_BYCALLER); ++ (void) fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" diff --git a/SOURCES/0621-units-set-StopWhenUnneeded-for-the-user-slice-units-.patch b/SOURCES/0621-units-set-StopWhenUnneeded-for-the-user-slice-units-.patch new file mode 100644 index 0000000..4b9bb79 --- /dev/null +++ b/SOURCES/0621-units-set-StopWhenUnneeded-for-the-user-slice-units-.patch @@ -0,0 +1,27 @@ +From f94c1bbec9e2c3efcbafd61ea1fdf8dbc3245d1b Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Aug 2018 20:19:38 +0200 +Subject: [PATCH] units: set StopWhenUnneeded= for the user slice units too + +We'd like them to go away, just like the user-runtime-dir@.service when +they aren't needed anymore. + +(cherry picked from commit 1007473b49b5aaeef0e53cd4a15f4ed8cf721926) + +Related: #1642460 +--- + units/user-.slice.d/10-defaults.conf | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/user-.slice.d/10-defaults.conf b/units/user-.slice.d/10-defaults.conf +index efc9d37c8e..1147e7aed9 100644 +--- a/units/user-.slice.d/10-defaults.conf ++++ b/units/user-.slice.d/10-defaults.conf +@@ -10,6 +10,7 @@ + [Unit] + Description=User Slice of UID %j + After=systemd-user-sessions.service ++StopWhenUnneeded=yes + + [Slice] + TasksMax=80% diff --git a/SOURCES/0622-units-improve-Description-string-a-bit.patch b/SOURCES/0622-units-improve-Description-string-a-bit.patch new file mode 100644 index 0000000..dff8053 --- /dev/null +++ b/SOURCES/0622-units-improve-Description-string-a-bit.patch @@ -0,0 +1,29 @@ +From 50a4e03d2da89df32f2f63eb56051d789508ae75 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 6 Aug 2018 18:15:07 +0200 +Subject: [PATCH] units: improve Description= string a bit + +Let's not use the word "wrapper", as it's not clear what that is, and in +some way any unit file is a "wrapper"... let's simply say that it's +about the runtime directory. + +(cherry picked from commit 14df094a51e87013d96ac697ae4f14593cbcad39) + +Related: #1642460 +--- + units/user-runtime-dir@.service.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/user-runtime-dir@.service.in b/units/user-runtime-dir@.service.in +index bfd6488d61..63db1cca6a 100644 +--- a/units/user-runtime-dir@.service.in ++++ b/units/user-runtime-dir@.service.in +@@ -8,7 +8,7 @@ + # (at your option) any later version. + + [Unit] +-Description=/run/user/%i mount wrapper ++Description=User runtime directory /run/user/%i + After=systemd-user-sessions.service + StopWhenUnneeded=yes + diff --git a/SOURCES/0623-logind-improve-logging-in-manager_connect_console.patch b/SOURCES/0623-logind-improve-logging-in-manager_connect_console.patch new file mode 100644 index 0000000..6a30f47 --- /dev/null +++ b/SOURCES/0623-logind-improve-logging-in-manager_connect_console.patch @@ -0,0 +1,77 @@ +From 9e9c6cbbdd60f4538cee041ffe3f9cd831c5de17 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 3 Aug 2018 20:21:27 +0200 +Subject: [PATCH] logind: improve logging in manager_connect_console() + +let's make sure we log about every failure + +Also, complain about systems where /dev/tty0 exists but +/sys/class/tty/tty0/active does not. Such systems (usually container +environments) are pretty broken as they mount something that is not a VC +to /dev/tty0 and they really shouldn't. + +Systems should either have a VC or not, but not badly fake one by +mounting things wildly. + +This just adds a warning message, as before we'll simply turn off VC +handling in this case. + +(cherry picked from commit 0b6d55cae9b8adc507fbea95d1b2874729a77386) + +Related: #1642460 +--- + src/login/logind.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/login/logind.c b/src/login/logind.c +index 52fcee933c..1b366cd55f 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -815,28 +815,28 @@ static int manager_connect_console(Manager *m) { + assert(m); + assert(m->console_active_fd < 0); + +- /* On certain architectures (S390 and Xen, and containers), +- /dev/tty0 does not exist, so don't fail if we can't open +- it. */ ++ /* On certain systems (such as S390, Xen, and containers) /dev/tty0 does not exist (as there is no VC), so ++ * don't fail if we can't open it. */ ++ + if (access("/dev/tty0", F_OK) < 0) + return 0; + + m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (m->console_active_fd < 0) { + +- /* On some systems the device node /dev/tty0 may exist +- * even though /sys/class/tty/tty0 does not. */ +- if (errno == ENOENT) ++ /* On some systems /dev/tty0 may exist even though /sys/class/tty/tty0 does not. These are broken, but ++ * common. Let's complain but continue anyway. */ ++ if (errno == ENOENT) { ++ log_warning_errno(errno, "System has /dev/tty0 but not /sys/class/tty/tty0/active which is broken, ignoring: %m"); + return 0; ++ } + + return log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m"); + } + + r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m); +- if (r < 0) { +- log_error("Failed to watch foreground console"); +- return r; +- } ++ if (r < 0) ++ return log_error_errno(r, "Failed to watch foreground console: %m"); + + /* + * SIGRTMIN is used as global VT-release signal, SIGRTMIN + 1 is used +@@ -855,7 +855,7 @@ static int manager_connect_console(Manager *m) { + + r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m); + if (r < 0) +- return r; ++ return log_error_errno(r, "Failed to subscribe to signal: %m"); + + return 0; + } diff --git a/SOURCES/0624-logind-save-restore-User-object-s-stopping-field-dur.patch b/SOURCES/0624-logind-save-restore-User-object-s-stopping-field-dur.patch new file mode 100644 index 0000000..d640d09 --- /dev/null +++ b/SOURCES/0624-logind-save-restore-User-object-s-stopping-field-dur.patch @@ -0,0 +1,90 @@ +From 4703c08fe3a8bfa1bc9b893e8bde365b1cbeffd9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 6 Aug 2018 18:14:11 +0200 +Subject: [PATCH] logind: save/restore User object's "stopping" field during + restarts + +Whether we are stopping or not is highly relevant, hence don't forget it +across restarts. + +(cherry picked from commit d865bc024bf28c17120d7322a81e9a99997a59f6) + +Related: #1642460 +--- + src/login/logind-user.c | 20 +++++++++++++++----- + src/login/logind-user.h | 5 +++-- + 2 files changed, 18 insertions(+), 7 deletions(-) + +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 17ed361411..35b2ca5489 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -136,9 +136,11 @@ static int user_save_internal(User *u) { + fprintf(f, + "# This is private data. Do not parse.\n" + "NAME=%s\n" +- "STATE=%s\n", ++ "STATE=%s\n" /* friendly user-facing state */ ++ "STOPPING=%s\n", /* low-level state */ + u->name, +- user_state_to_string(user_get_state(u))); ++ user_state_to_string(user_get_state(u)), ++ yes_no(u->stopping)); + + /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */ + if (u->runtime_path) +@@ -277,14 +279,14 @@ int user_save(User *u) { + } + + int user_load(User *u) { +- _cleanup_free_ char *realtime = NULL, *monotonic = NULL; ++ _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *stopping = NULL; + int r; + + assert(u); + + r = parse_env_file(NULL, u->state_file, NEWLINE, + "SERVICE_JOB", &u->service_job, +- "SLICE_JOB", &u->slice_job, ++ "STOPPING", &stopping, + "REALTIME", &realtime, + "MONOTONIC", &monotonic, + NULL); +@@ -293,12 +295,20 @@ int user_load(User *u) { + if (r < 0) + return log_error_errno(r, "Failed to read %s: %m", u->state_file); + ++ if (stopping) { ++ r = parse_boolean(stopping); ++ if (r < 0) ++ log_debug_errno(r, "Failed to parse 'STOPPING' boolean: %s", stopping); ++ else ++ u->stopping = r; ++ } ++ + if (realtime) + timestamp_deserialize(realtime, &u->timestamp.realtime); + if (monotonic) + timestamp_deserialize(monotonic, &u->timestamp.monotonic); + +- return r; ++ return 0; + } + + static int user_start_service(User *u) { +diff --git a/src/login/logind-user.h b/src/login/logind-user.h +index eba2325284..03e020b870 100644 +--- a/src/login/logind-user.h ++++ b/src/login/logind-user.h +@@ -36,8 +36,9 @@ struct User { + dual_timestamp timestamp; + + bool in_gc_queue:1; +- bool started:1; +- bool stopping:1; ++ ++ bool started:1; /* Whenever the user being started, has been started or is being stopped again. */ ++ bool stopping:1; /* Whenever the user is being stopped or has been stopped. */ + + LIST_HEAD(Session, sessions); + LIST_FIELDS(User, gc_queue); diff --git a/SOURCES/0625-logind-correct-bad-clean-up-path.patch b/SOURCES/0625-logind-correct-bad-clean-up-path.patch new file mode 100644 index 0000000..90740cc --- /dev/null +++ b/SOURCES/0625-logind-correct-bad-clean-up-path.patch @@ -0,0 +1,25 @@ +From eebbeada76b0fa4e252ecf4e25b088733636fe89 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 6 Aug 2018 18:19:45 +0200 +Subject: [PATCH] logind: correct bad clean-up path + +(cherry picked from commit d88ffeeeefda4c3447223fd36f8e30f23c931e48) + +Related: #1642460 +--- + src/login/logind-dbus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index ae9abc9bce..4b2c418453 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -845,7 +845,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus + + r = sd_bus_message_enter_container(message, 'a', "(sv)"); + if (r < 0) +- return r; ++ goto fail; + + r = session_start(session, message); + if (r < 0) diff --git a/SOURCES/0626-logind-fix-bad-error-propagation.patch b/SOURCES/0626-logind-fix-bad-error-propagation.patch new file mode 100644 index 0000000..1a07e78 --- /dev/null +++ b/SOURCES/0626-logind-fix-bad-error-propagation.patch @@ -0,0 +1,25 @@ +From 7662d7c86d1fbb01693d4eb008fa27bf1e0030a9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 6 Aug 2018 18:21:37 +0200 +Subject: [PATCH] logind: fix bad error propagation + +(cherry picked from commit cce08496e7353e3e9903b42695aba3f9d259b90a) + +Related: #1642460 +--- + src/login/logind-seat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c +index f68fc0ceaa..9e4f009643 100644 +--- a/src/login/logind-seat.c ++++ b/src/login/logind-seat.c +@@ -175,7 +175,7 @@ static int vt_allocate(unsigned int vtnr) { + xsprintf(p, "/dev/tty%u", vtnr); + fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) +- return -errno; ++ return fd; + + return 0; + } diff --git a/SOURCES/0627-logind-never-elect-a-session-that-is-stopping-as-dis.patch b/SOURCES/0627-logind-never-elect-a-session-that-is-stopping-as-dis.patch new file mode 100644 index 0000000..145c425 --- /dev/null +++ b/SOURCES/0627-logind-never-elect-a-session-that-is-stopping-as-dis.patch @@ -0,0 +1,42 @@ +From 35f9a7f8f4e8917725349fe764706658c02537ca Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 6 Aug 2018 19:02:29 +0200 +Subject: [PATCH] logind: never elect a session that is stopping as display + +(cherry picked from commit 04857cd801022d9f9933efb484c6253572f09870) + +Related: #1642460 +--- + src/login/logind-user.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 35b2ca5489..3e4c99bdbd 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -613,11 +613,10 @@ int user_kill(User *u, int signo) { + } + + static bool elect_display_filter(Session *s) { +- /* Return true if the session is a candidate for the user’s ‘primary +- * session’ or ‘display’. */ ++ /* Return true if the session is a candidate for the user’s ‘primary session’ or ‘display’. */ + assert(s); + +- return (s->class == SESSION_USER && !s->stopping); ++ return s->class == SESSION_USER && s->started && !s->stopping; + } + + static int elect_display_compare(Session *s1, Session *s2) { +@@ -663,9 +662,8 @@ void user_elect_display(User *u) { + + assert(u); + +- /* This elects a primary session for each user, which we call +- * the "display". We try to keep the assignment stable, but we +- * "upgrade" to better choices. */ ++ /* This elects a primary session for each user, which we call the "display". We try to keep the assignment ++ * stable, but we "upgrade" to better choices. */ + log_debug("Electing new display for user %s", u->name); + + LIST_FOREACH(sessions_by_user, s, u->sessions) { diff --git a/SOURCES/0628-logind-introduce-little-helper-that-checks-whether-a.patch b/SOURCES/0628-logind-introduce-little-helper-that-checks-whether-a.patch new file mode 100644 index 0000000..d50750b --- /dev/null +++ b/SOURCES/0628-logind-introduce-little-helper-that-checks-whether-a.patch @@ -0,0 +1,60 @@ +From 83c49a5e54dffc3dfa85b79f6375cd0a42a4ff76 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 6 Aug 2018 19:34:39 +0200 +Subject: [PATCH] logind: introduce little helper that checks whether a session + is ready + +(cherry picked from commit b1951bc83ffbbb92ba4de7b9cba845421c2f35b1) + +Related: #1642460 +--- + src/login/logind-session-dbus.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c +index 88a2d33dc8..03585b7f8e 100644 +--- a/src/login/logind-session-dbus.c ++++ b/src/login/logind-session-dbus.c +@@ -704,6 +704,15 @@ int session_send_lock_all(Manager *m, bool lock) { + return r; + } + ++static bool session_ready(Session *s) { ++ assert(s); ++ ++ /* Returns true when the session is ready, i.e. all jobs we enqueued for it are done (regardless if successful or not) */ ++ ++ return !s->scope_job && ++ !s->user->service_job; ++} ++ + int session_send_create_reply(Session *s, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL; + _cleanup_close_ int fifo_fd = -1; +@@ -711,14 +720,13 @@ int session_send_create_reply(Session *s, sd_bus_error *error) { + + assert(s); + +- /* This is called after the session scope and the user service +- * were successfully created, and finishes where ++ /* This is called after the session scope and the user service were successfully created, and finishes where + * bus_manager_create_session() left off. */ + + if (!s->create_message) + return 0; + +- if (!sd_bus_error_is_set(error) && (s->scope_job || s->user->service_job)) ++ if (!sd_bus_error_is_set(error) && !session_ready(s)) + return 0; + + c = s->create_message; +@@ -731,8 +739,7 @@ int session_send_create_reply(Session *s, sd_bus_error *error) { + if (fifo_fd < 0) + return fifo_fd; + +- /* Update the session state file before we notify the client +- * about the result. */ ++ /* Update the session state file before we notify the client about the result. */ + session_save(s); + + p = session_bus_path(s); diff --git a/SOURCES/0629-logind-propagate-session-stop-errors.patch b/SOURCES/0629-logind-propagate-session-stop-errors.patch new file mode 100644 index 0000000..feed8cb --- /dev/null +++ b/SOURCES/0629-logind-propagate-session-stop-errors.patch @@ -0,0 +1,40 @@ +From 31aa21a13f9b91486b1a95c5b73fa088af77fcb4 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 6 Aug 2018 19:35:44 +0200 +Subject: [PATCH] logind: propagate session stop errors + +Let's propagate errors from stopping sessions via seat_stop(). This is +similar to how we propagate such errors in user_stop() for all sessions +associated with a user. + +Note that we propagate these errors, but we don't abort the function. + +(cherry picked from commit e6958b7ea33813b085966ac25817a957c0dad7f9) + +Related: #1642460 +--- + src/login/logind-seat.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c +index 9e4f009643..96c34a6c9e 100644 +--- a/src/login/logind-seat.c ++++ b/src/login/logind-seat.c +@@ -431,7 +431,7 @@ int seat_start(Seat *s) { + } + + int seat_stop(Seat *s, bool force) { +- int r = 0; ++ int r; + + assert(s); + +@@ -441,7 +441,7 @@ int seat_stop(Seat *s, bool force) { + "SEAT_ID=%s", s->id, + LOG_MESSAGE("Removed seat %s.", s->id)); + +- seat_stop_sessions(s, force); ++ r = seat_stop_sessions(s, force); + + unlink(s->state_file); + seat_add_to_gc_queue(s); diff --git a/SOURCES/0630-logind-rework-how-we-manage-the-slice-and-user-runti.patch b/SOURCES/0630-logind-rework-how-we-manage-the-slice-and-user-runti.patch new file mode 100644 index 0000000..7880086 --- /dev/null +++ b/SOURCES/0630-logind-rework-how-we-manage-the-slice-and-user-runti.patch @@ -0,0 +1,618 @@ +From a05c1077911652954c8b9e82cfdc0fc643eca782 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 6 Aug 2018 21:44:45 +0200 +Subject: [PATCH] logind: rework how we manage the slice and + user-runtime-dir@.service unit for each user + +Instead of managing it explicitly, let's simplify things and rely on +regular Wants=/Requires= dependencies to pull in these units from +user@.service and the session scope, and StopWhenUneeded= to stop these +auxiliary units again. This way, they can be pulled in easily by +unrelated units too. + +This simplifies things quite a bit: for each session we now only need to +manage the session scope, and for each user the user@.service, the other +units are not something we need to manage anymore. + +This patch also makes sure that if user@.service of a user is masked we +will continue to work, and user-runtime-dir@.service will still be +correctly pulled in, as it is now a dependency of the scope unit. + +Fixes: #9461 +Replaces: #5546 +(cherry picked from commit 25a1ab4ed48b72e974f77a68dcbe3521014787bb) + +Related: #1642460 +--- + src/login/logind-dbus.c | 58 ++++++++-------- + src/login/logind-session.c | 64 ++++++++++-------- + src/login/logind-session.h | 2 +- + src/login/logind-user.c | 134 ++++++++++++++----------------------- + src/login/logind-user.h | 7 +- + src/login/logind.c | 2 +- + src/login/logind.h | 2 +- + 7 files changed, 123 insertions(+), 146 deletions(-) + +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 4b2c418453..7eba617fff 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -847,7 +847,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus + if (r < 0) + goto fail; + +- r = session_start(session, message); ++ r = session_start(session, message, error); + if (r < 0) + goto fail; + +@@ -3110,24 +3110,20 @@ const sd_bus_vtable manager_vtable[] = { + }; + + static int session_jobs_reply(Session *s, const char *unit, const char *result) { +- int r = 0; +- + assert(s); + assert(unit); + + if (!s->started) +- return r; ++ return 0; + +- if (streq(result, "done")) +- r = session_send_create_reply(s, NULL); +- else { ++ if (result && !streq(result, "done")) { + _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; + +- sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result); +- r = session_send_create_reply(s, &e); ++ sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit '%s' failed with '%s'", unit, result); ++ return session_send_create_reply(s, &e); + } + +- return r; ++ return session_send_create_reply(s, NULL); + } + + int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) { +@@ -3160,30 +3156,29 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err + } + + session = hashmap_get(m->session_units, unit); +- if (session && streq_ptr(path, session->scope_job)) { +- session->scope_job = mfree(session->scope_job); +- session_jobs_reply(session, unit, result); ++ if (session) { ++ if (streq_ptr(path, session->scope_job)) { ++ session->scope_job = mfree(session->scope_job); ++ (void) session_jobs_reply(session, unit, result); ++ ++ session_save(session); ++ user_save(session->user); ++ } + +- session_save(session); +- user_save(session->user); + session_add_to_gc_queue(session); + } + + user = hashmap_get(m->user_units, unit); +- if (user && +- (streq_ptr(path, user->service_job) || +- streq_ptr(path, user->slice_job))) { +- +- if (streq_ptr(path, user->service_job)) ++ if (user) { ++ if (streq_ptr(path, user->service_job)) { + user->service_job = mfree(user->service_job); + +- if (streq_ptr(path, user->slice_job)) +- user->slice_job = mfree(user->slice_job); ++ LIST_FOREACH(sessions_by_user, session, user->sessions) ++ (void) session_jobs_reply(session, unit, NULL /* don't propagate user service failures to the client */); + +- LIST_FOREACH(sessions_by_user, session, user->sessions) +- session_jobs_reply(session, unit, result); ++ user_save(user); ++ } + +- user_save(user); + user_add_to_gc_queue(user); + } + +@@ -3315,13 +3310,14 @@ int manager_start_scope( + pid_t pid, + const char *slice, + const char *description, +- const char *after, +- const char *after2, ++ char **wants, ++ char **after, + sd_bus_message *more_properties, + sd_bus_error *error, + char **job) { + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; ++ char **i; + int r; + + assert(manager); +@@ -3359,14 +3355,14 @@ int manager_start_scope( + return r; + } + +- if (!isempty(after)) { +- r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after); ++ STRV_FOREACH(i, wants) { ++ r = sd_bus_message_append(m, "(sv)", "Wants", "as", 1, *i); + if (r < 0) + return r; + } + +- if (!isempty(after2)) { +- r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2); ++ STRV_FOREACH(i, after) { ++ r = sd_bus_message_append(m, "(sv)", "After", "as", 1, *i); + if (r < 0) + return r; + } +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 960a24d1a7..d56b48a732 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -27,6 +27,7 @@ + #include "path-util.h" + #include "process-util.h" + #include "string-table.h" ++#include "strv.h" + #include "terminal-util.h" + #include "user-util.h" + #include "util.h" +@@ -560,17 +561,18 @@ int session_activate(Session *s) { + return 0; + } + +-static int session_start_scope(Session *s, sd_bus_message *properties) { ++static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_error *error) { + int r; + + assert(s); + assert(s->user); + + if (!s->scope) { +- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- char *scope, *job = NULL; ++ _cleanup_free_ char *scope = NULL; + const char *description; + ++ s->scope_job = mfree(s->scope_job); ++ + scope = strjoin("session-", s->id, ".scope"); + if (!scope) + return log_oom(); +@@ -583,21 +585,15 @@ static int session_start_scope(Session *s, sd_bus_message *properties) { + s->leader, + s->user->slice, + description, +- "systemd-logind.service", +- "systemd-user-sessions.service", ++ STRV_MAKE(s->user->runtime_dir_service, s->user->service), /* These two have StopWhenUnneeded= set, hence add a dep towards them */ ++ STRV_MAKE("systemd-logind.service", "systemd-user-sessions.service", s->user->runtime_dir_service, s->user->service), /* And order us after some more */ + properties, +- &error, +- &job); +- if (r < 0) { +- log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r)); +- free(scope); +- return r; +- } else { +- s->scope = scope; ++ error, ++ &s->scope_job); ++ if (r < 0) ++ return log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(error, r)); + +- free(s->scope_job); +- s->scope_job = job; +- } ++ s->scope = TAKE_PTR(scope); + } + + if (s->scope) +@@ -606,7 +602,7 @@ static int session_start_scope(Session *s, sd_bus_message *properties) { + return 0; + } + +-int session_start(Session *s, sd_bus_message *properties) { ++int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) { + int r; + + assert(s); +@@ -614,6 +610,9 @@ int session_start(Session *s, sd_bus_message *properties) { + if (!s->user) + return -ESTALE; + ++ if (s->stopping) ++ return -EINVAL; ++ + if (s->started) + return 0; + +@@ -621,8 +620,7 @@ int session_start(Session *s, sd_bus_message *properties) { + if (r < 0) + return r; + +- /* Create cgroup */ +- r = session_start_scope(s, properties); ++ r = session_start_scope(s, properties, error); + if (r < 0) + return r; + +@@ -673,21 +671,24 @@ static int session_stop_scope(Session *s, bool force) { + * that is left in the scope is "left-over". Informing systemd about this has the benefit that it will log + * when killing any processes left after this point. */ + r = manager_abandon_scope(s->manager, s->scope, &error); +- if (r < 0) ++ if (r < 0) { + log_warning_errno(r, "Failed to abandon session scope, ignoring: %s", bus_error_message(&error, r)); ++ sd_bus_error_free(&error); ++ } ++ ++ s->scope_job = mfree(s->scope_job); + + /* Optionally, let's kill everything that's left now. */ + if (force || manager_shall_kill(s->manager, s->user->name)) { +- char *job = NULL; + +- r = manager_stop_unit(s->manager, s->scope, &error, &job); +- if (r < 0) +- return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r)); ++ r = manager_stop_unit(s->manager, s->scope, &error, &s->scope_job); ++ if (r < 0) { ++ if (force) ++ return log_error_errno(r, "Failed to stop session scope: %s", bus_error_message(&error, r)); + +- free(s->scope_job); +- s->scope_job = job; ++ log_warning_errno(r, "Failed to stop session scope, ignoring: %s", bus_error_message(&error, r)); ++ } + } else { +- s->scope_job = mfree(s->scope_job); + + /* With no killing, this session is allowed to persist in "closing" state indefinitely. + * Therefore session stop and session removal may be two distinct events. +@@ -707,8 +708,17 @@ int session_stop(Session *s, bool force) { + + assert(s); + ++ /* This is called whenever we begin with tearing down a session record. It's called in four cases: explicit API ++ * request via the bus (either directly for the session object or for the seat or user object this session ++ * belongs to; 'force' is true), or due to automatic GC (i.e. scope vanished; 'force' is false), or because the ++ * session FIFO saw an EOF ('force' is false), or because the release timer hit ('force' is false). */ ++ + if (!s->user) + return -ESTALE; ++ if (!s->started) ++ return 0; ++ if (s->stopping) ++ return 0; + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index 572f2545c1..7d17d9a25f 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -124,7 +124,7 @@ void session_set_idle_hint(Session *s, bool b); + int session_get_locked_hint(Session *s); + void session_set_locked_hint(Session *s, bool b); + int session_create_fifo(Session *s); +-int session_start(Session *s, sd_bus_message *properties); ++int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error); + int session_stop(Session *s, bool force); + int session_finalize(Session *s); + int session_release(Session *s); +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 3e4c99bdbd..39fc76f4dc 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -68,6 +68,10 @@ int user_new(User **ret, Manager *m, uid_t uid, gid_t gid, const char *name) { + if (r < 0) + return r; + ++ r = unit_name_build("user-runtime-dir", lu, ".service", &u->runtime_dir_service); ++ if (r < 0) ++ return r; ++ + r = hashmap_put(m->users, UID_TO_PTR(uid), u); + if (r < 0) + return r; +@@ -80,6 +84,10 @@ int user_new(User **ret, Manager *m, uid_t uid, gid_t gid, const char *name) { + if (r < 0) + return r; + ++ r = hashmap_put(m->user_units, u->runtime_dir_service, u); ++ if (r < 0) ++ return r; ++ + *ret = TAKE_PTR(u); + return 0; + } +@@ -97,15 +105,18 @@ User *user_free(User *u) { + if (u->service) + hashmap_remove_value(u->manager->user_units, u->service, u); + ++ if (u->runtime_dir_service) ++ hashmap_remove_value(u->manager->user_units, u->runtime_dir_service, u); ++ + if (u->slice) + hashmap_remove_value(u->manager->user_units, u->slice, u); + + hashmap_remove_value(u->manager->users, UID_TO_PTR(u->uid), u); + +- u->slice_job = mfree(u->slice_job); + u->service_job = mfree(u->service_job); + + u->service = mfree(u->service); ++ u->runtime_dir_service = mfree(u->runtime_dir_service); + u->slice = mfree(u->slice); + u->runtime_path = mfree(u->runtime_path); + u->state_file = mfree(u->state_file); +@@ -149,9 +160,6 @@ static int user_save_internal(User *u) { + if (u->service_job) + fprintf(f, "SERVICE_JOB=%s\n", u->service_job); + +- if (u->slice_job) +- fprintf(f, "SLICE_JOB=%s\n", u->slice_job); +- + if (u->display) + fprintf(f, "DISPLAY=%s\n", u->display->id); + +@@ -311,66 +319,46 @@ int user_load(User *u) { + return 0; + } + +-static int user_start_service(User *u) { ++static void user_start_service(User *u) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- char *job; + int r; + + assert(u); + ++ /* Start the service containing the "systemd --user" instance (user@.service). Note that we don't explicitly ++ * start the per-user slice or the systemd-runtime-dir@.service instance, as those are pulled in both by ++ * user@.service and the session scopes as dependencies. */ ++ + u->service_job = mfree(u->service_job); + +- r = manager_start_unit( +- u->manager, +- u->service, +- &error, +- &job); ++ r = manager_start_unit(u->manager, u->service, &error, &u->service_job); + if (r < 0) + /* we don't fail due to this, let's try to continue */ + log_full_errno(sd_bus_error_has_name(&error, BUS_ERROR_UNIT_MASKED) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r)); +- else +- u->service_job = job; +- +- return 0; + } + + int user_start(User *u) { +- int r; +- + assert(u); + + if (u->started && !u->stopping) + return 0; + +- /* +- * If u->stopping is set, the user is marked for removal and the slice +- * and service stop-jobs are queued. We have to clear that flag before +- * queing the start-jobs again. If they succeed, the user object can be +- * re-used just fine (pid1 takes care of job-ordering and proper +- * restart), but if they fail, we want to force another user_stop() so +- * possibly pending units are stopped. +- * Note that we don't clear u->started, as we have no clue what state +- * the user is in on failure here. Hence, we pretend the user is +- * running so it will be properly taken down by GC. However, we clearly +- * return an error from user_start() in that case, so no further +- * reference to the user is taken. +- */ ++ /* If u->stopping is set, the user is marked for removal and service stop-jobs are queued. We have to clear ++ * that flag before queing the start-jobs again. If they succeed, the user object can be re-used just fine ++ * (pid1 takes care of job-ordering and proper restart), but if they fail, we want to force another user_stop() ++ * so possibly pending units are stopped. */ + u->stopping = false; + + if (!u->started) + log_debug("Starting services for new user %s.", u->name); + +- /* Save the user data so far, because pam_systemd will read the +- * XDG_RUNTIME_DIR out of it while starting up systemd --user. +- * We need to do user_save_internal() because we have not +- * "officially" started yet. */ ++ /* Save the user data so far, because pam_systemd will read the XDG_RUNTIME_DIR out of it while starting up ++ * systemd --user. We need to do user_save_internal() because we have not "officially" started yet. */ + user_save_internal(u); + +- /* Spawn user systemd */ +- r = user_start_service(u); +- if (r < 0) +- return r; ++ /* Start user@UID.service */ ++ user_start_service(u); + + if (!u->started) { + if (!dual_timestamp_is_set(&u->timestamp)) +@@ -385,68 +373,50 @@ int user_start(User *u) { + return 0; + } + +-static int user_stop_slice(User *u) { ++static void user_stop_service(User *u) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- char *job; + int r; + + assert(u); ++ assert(u->service); + +- r = manager_stop_unit(u->manager, u->slice, &error, &job); +- if (r < 0) { +- log_error("Failed to stop user slice: %s", bus_error_message(&error, r)); +- return r; +- } ++ /* The reverse of user_start_service(). Note that we only stop user@UID.service here, and let StopWhenUnneeded= ++ * deal with the slice and the user-runtime-dir@.service instance. */ + +- free(u->slice_job); +- u->slice_job = job; +- +- return r; +-} +- +-static int user_stop_service(User *u) { +- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; +- char *job; +- int r; +- +- assert(u); +- +- r = manager_stop_unit(u->manager, u->service, &error, &job); +- if (r < 0) { +- log_error("Failed to stop user service: %s", bus_error_message(&error, r)); +- return r; +- } ++ u->service_job = mfree(u->service_job); + +- free_and_replace(u->service_job, job); +- return r; ++ r = manager_stop_unit(u->manager, u->service, &error, &u->service_job); ++ if (r < 0) ++ log_warning_errno(r, "Failed to stop user service '%s', ignoring: %s", u->service, bus_error_message(&error, r)); + } + + int user_stop(User *u, bool force) { + Session *s; +- int r = 0, k; ++ int r = 0; + assert(u); + +- /* Stop jobs have already been queued */ +- if (u->stopping) { ++ /* This is called whenever we begin with tearing down a user record. It's called in two cases: explicit API ++ * request to do so via the bus (in which case 'force' is true) and automatically due to GC, if there's no ++ * session left pinning it (in which case 'force' is false). Note that this just initiates tearing down of the ++ * user, the User object will remain in memory until user_finalize() is called, see below. */ ++ ++ if (!u->started) ++ return 0; ++ ++ if (u->stopping) { /* Stop jobs have already been queued */ + user_save(u); +- return r; ++ return 0; + } + + LIST_FOREACH(sessions_by_user, s, u->sessions) { ++ int k; ++ + k = session_stop(s, force); + if (k < 0) + r = k; + } + +- /* Kill systemd */ +- k = user_stop_service(u); +- if (k < 0) +- r = k; +- +- /* Kill cgroup */ +- k = user_stop_slice(u); +- if (k < 0) +- r = k; ++ user_stop_service(u); + + u->stopping = true; + +@@ -461,6 +431,9 @@ int user_finalize(User *u) { + + assert(u); + ++ /* Called when the user is really ready to be freed, i.e. when all unit stop jobs and suchlike for it are ++ * done. This is called as a result of an earlier user_done() when all jobs are completed. */ ++ + if (u->started) + log_debug("User %s logged out.", u->name); + +@@ -554,9 +527,6 @@ bool user_may_gc(User *u, bool drop_not_started) { + if (user_check_linger_file(u) > 0) + return false; + +- if (u->slice_job && manager_job_is_active(u->manager, u->slice_job)) +- return false; +- + if (u->service_job && manager_job_is_active(u->manager, u->service_job)) + return false; + +@@ -581,7 +551,7 @@ UserState user_get_state(User *u) { + if (u->stopping) + return USER_CLOSING; + +- if (!u->started || u->slice_job || u->service_job) ++ if (!u->started || u->service_job) + return USER_OPENING; + + if (u->sessions) { +diff --git a/src/login/logind-user.h b/src/login/logind-user.h +index 03e020b870..5e1f7b813a 100644 +--- a/src/login/logind-user.h ++++ b/src/login/logind-user.h +@@ -25,11 +25,12 @@ struct User { + char *name; + char *state_file; + char *runtime_path; +- char *slice; +- char *service; ++ ++ char *slice; /* user-UID.slice */ ++ char *service; /* user@UID.service */ ++ char *runtime_dir_service; /* user-runtime-dir@UID.service */ + + char *service_job; +- char *slice_job; + + Session *display; + +diff --git a/src/login/logind.c b/src/login/logind.c +index 1b366cd55f..6c208c8e89 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -1158,7 +1158,7 @@ static int manager_startup(Manager *m) { + user_start(user); + + HASHMAP_FOREACH(session, m->sessions, i) +- session_start(session, NULL); ++ (void) session_start(session, NULL, NULL); + + HASHMAP_FOREACH(inhibitor, m->inhibitors, i) + inhibitor_start(inhibitor); +diff --git a/src/login/logind.h b/src/login/logind.h +index a6ebc9e152..ae4d74076b 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -161,7 +161,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name + + int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_; + +-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_message *more_properties, sd_bus_error *error, char **job); ++int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, char **wants, char **after, sd_bus_message *more_properties, sd_bus_error *error, char **job); + int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); + int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); + int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error); diff --git a/SOURCES/0631-logind-optionally-keep-the-user-.service-instance-fo.patch b/SOURCES/0631-logind-optionally-keep-the-user-.service-instance-fo.patch new file mode 100644 index 0000000..63f6a56 --- /dev/null +++ b/SOURCES/0631-logind-optionally-keep-the-user-.service-instance-fo.patch @@ -0,0 +1,291 @@ +From 35455408393cb29a5e49fd769c4823b6a6f886b4 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 7 Aug 2018 11:02:00 +0200 +Subject: [PATCH] logind: optionally, keep the user@.service instance for + eached logged in user around for a while + +This should speed up rapid logout/login cycles a bit. + +By default this timeout is now set to 10s. + +Fixes: #8410 +Replaces: #4434 +(cherry picked from commit 9afe9efb9340588db553950727a2a9672dc3db24) + +Resolves: #1642460 +--- + man/logind.conf.xml | 11 +++++ + src/login/logind-core.c | 2 + + src/login/logind-dbus.c | 1 + + src/login/logind-gperf.gperf | 1 + + src/login/logind-session.c | 4 ++ + src/login/logind-user.c | 88 +++++++++++++++++++++++++++++++++--- + src/login/logind-user.h | 7 ++- + src/login/logind.h | 1 + + 8 files changed, 107 insertions(+), 8 deletions(-) + +diff --git a/man/logind.conf.xml b/man/logind.conf.xml +index 7d7e869a26..0cf8a7d1f2 100644 +--- a/man/logind.conf.xml ++++ b/man/logind.conf.xml +@@ -184,6 +184,17 @@ + 5. + + ++ ++ UserStopDelaySec= ++ ++ Specifies how long to keep the user record and per-user service ++ user@.service around for a user after they logged out fully. If set to zero, the per-user ++ service is terminated immediately when the last session of the user has ended. If this option is configured to ++ non-zero rapid logout/login cycles are sped up, as the user's service manager is not constantly restarted. If ++ set to infinity the per-user service for a user is never terminated again after first login, ++ and continues to run until system shutdown. Defaults to 10s. ++ ++ + + HandlePowerKey= + HandleSuspendKey= +diff --git a/src/login/logind-core.c b/src/login/logind-core.c +index f598bbaa1c..678c708df1 100644 +--- a/src/login/logind-core.c ++++ b/src/login/logind-core.c +@@ -27,6 +27,8 @@ void manager_reset_config(Manager *m) { + m->reserve_vt = 6; + m->remove_ipc = false; + m->inhibit_delay_max = 5 * USEC_PER_SEC; ++ m->user_stop_delay = 10 * USEC_PER_SEC; ++ + m->handle_power_key = HANDLE_POWEROFF; + m->handle_suspend_key = HANDLE_SUSPEND; + m->handle_hibernate_key = HANDLE_HIBERNATE; +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 7eba617fff..6586280269 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -2695,6 +2695,7 @@ const sd_bus_vtable manager_vtable[] = { + SD_BUS_PROPERTY("BlockInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("DelayInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("InhibitDelayMaxUSec", "t", NULL, offsetof(Manager, inhibit_delay_max), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("UserStopDelayUSec", "t", NULL, offsetof(Manager, user_stop_delay), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST), +diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf +index c85339dcd3..8829ce7d85 100644 +--- a/src/login/logind-gperf.gperf ++++ b/src/login/logind-gperf.gperf +@@ -23,6 +23,7 @@ Login.KillUserProcesses, config_parse_bool, 0, offse + Login.KillOnlyUsers, config_parse_strv, 0, offsetof(Manager, kill_only_users) + Login.KillExcludeUsers, config_parse_strv, 0, offsetof(Manager, kill_exclude_users) + Login.InhibitDelayMaxSec, config_parse_sec, 0, offsetof(Manager, inhibit_delay_max) ++Login.UserStopDelaySec, config_parse_sec, 0, offsetof(Manager, user_stop_delay) + Login.HandlePowerKey, config_parse_handle_action, 0, offsetof(Manager, handle_power_key) + Login.HandleSuspendKey, config_parse_handle_action, 0, offsetof(Manager, handle_suspend_key) + Login.HandleHibernateKey, config_parse_handle_action, 0, offsetof(Manager, handle_hibernate_key) +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index d56b48a732..dd4ac9482a 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -101,6 +101,8 @@ Session* session_free(Session *s) { + + if (s->user->display == s) + s->user->display = NULL; ++ ++ user_update_last_session_timer(s->user); + } + + if (s->seat) { +@@ -142,6 +144,8 @@ void session_set_user(Session *s, User *u) { + + s->user = u; + LIST_PREPEND(sessions_by_user, u->sessions, s); ++ ++ user_update_last_session_timer(u); + } + + static void session_save_devices(Session *s, FILE *f) { +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 39fc76f4dc..f23fcbe674 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -47,6 +47,7 @@ int user_new(User **ret, Manager *m, uid_t uid, gid_t gid, const char *name) { + .manager = m, + .uid = uid, + .gid = gid, ++ .last_session_timestamp = USEC_INFINITY, + }; + + u->name = strdup(name); +@@ -113,6 +114,8 @@ User *user_free(User *u) { + + hashmap_remove_value(u->manager->users, UID_TO_PTR(u->uid), u); + ++ (void) sd_event_source_unref(u->timer_event_source); ++ + u->service_job = mfree(u->service_job); + + u->service = mfree(u->service); +@@ -170,6 +173,10 @@ static int user_save_internal(User *u) { + u->timestamp.realtime, + u->timestamp.monotonic); + ++ if (u->last_session_timestamp != USEC_INFINITY) ++ fprintf(f, "LAST_SESSION_TIMESTAMP=" USEC_FMT "\n", ++ u->last_session_timestamp); ++ + if (u->sessions) { + Session *i; + bool first; +@@ -287,16 +294,17 @@ int user_save(User *u) { + } + + int user_load(User *u) { +- _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *stopping = NULL; ++ _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *stopping = NULL, *last_session_timestamp = NULL; + int r; + + assert(u); + + r = parse_env_file(NULL, u->state_file, NEWLINE, +- "SERVICE_JOB", &u->service_job, +- "STOPPING", &stopping, +- "REALTIME", &realtime, +- "MONOTONIC", &monotonic, ++ "SERVICE_JOB", &u->service_job, ++ "STOPPING", &stopping, ++ "REALTIME", &realtime, ++ "MONOTONIC", &monotonic, ++ "LAST_SESSION_TIMESTAMP", &last_session_timestamp, + NULL); + if (r == -ENOENT) + return 0; +@@ -312,9 +320,11 @@ int user_load(User *u) { + } + + if (realtime) +- timestamp_deserialize(realtime, &u->timestamp.realtime); ++ (void) timestamp_deserialize(realtime, &u->timestamp.realtime); + if (monotonic) +- timestamp_deserialize(monotonic, &u->timestamp.monotonic); ++ (void) timestamp_deserialize(monotonic, &u->timestamp.monotonic); ++ if (last_session_timestamp) ++ (void) timestamp_deserialize(last_session_timestamp, &u->last_session_timestamp); + + return 0; + } +@@ -524,6 +534,17 @@ bool user_may_gc(User *u, bool drop_not_started) { + if (u->sessions) + return false; + ++ if (u->last_session_timestamp != USEC_INFINITY) { ++ /* All sessions have been closed. Let's see if we shall leave the user record around for a bit */ ++ ++ if (u->manager->user_stop_delay == USEC_INFINITY) ++ return false; /* Leave it around forever! */ ++ if (u->manager->user_stop_delay > 0 && ++ now(CLOCK_MONOTONIC) < usec_add(u->last_session_timestamp, u->manager->user_stop_delay)) ++ return false; /* Leave it around for a bit longer. */ ++ } ++ ++ /* Is this a user that shall stay around forever? */ + if (user_check_linger_file(u) > 0) + return false; + +@@ -649,6 +670,59 @@ void user_elect_display(User *u) { + } + } + ++static int user_stop_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) { ++ User *u = userdata; ++ ++ assert(u); ++ user_add_to_gc_queue(u); ++ ++ return 0; ++} ++ ++void user_update_last_session_timer(User *u) { ++ int r; ++ ++ assert(u); ++ ++ if (u->sessions) { ++ /* There are sessions, turn off the timer */ ++ u->last_session_timestamp = USEC_INFINITY; ++ u->timer_event_source = sd_event_source_unref(u->timer_event_source); ++ return; ++ } ++ ++ if (u->last_session_timestamp != USEC_INFINITY) ++ return; /* Timer already started */ ++ ++ u->last_session_timestamp = now(CLOCK_MONOTONIC); ++ ++ assert(!u->timer_event_source); ++ ++ if (u->manager->user_stop_delay == 0 || u->manager->user_stop_delay == USEC_INFINITY) ++ return; ++ ++ if (sd_event_get_state(u->manager->event) == SD_EVENT_FINISHED) { ++ log_debug("Not allocating user stop timeout, since we are already exiting."); ++ return; ++ } ++ ++ r = sd_event_add_time(u->manager->event, ++ &u->timer_event_source, ++ CLOCK_MONOTONIC, ++ usec_add(u->last_session_timestamp, u->manager->user_stop_delay), 0, ++ user_stop_timeout_callback, u); ++ if (r < 0) ++ log_warning_errno(r, "Failed to enqueue user stop event source, ignoring: %m"); ++ ++ if (DEBUG_LOGGING) { ++ char s[FORMAT_TIMESPAN_MAX]; ++ ++ log_debug("Last session of user '%s' logged out, terminating user context in %s.", ++ u->name, ++ format_timespan(s, sizeof(s), u->manager->user_stop_delay, USEC_PER_MSEC)); ++ } ++} ++ + static const char* const user_state_table[_USER_STATE_MAX] = { + [USER_OFFLINE] = "offline", + [USER_OPENING] = "opening", +diff --git a/src/login/logind-user.h b/src/login/logind-user.h +index 5e1f7b813a..e05646adc9 100644 +--- a/src/login/logind-user.h ++++ b/src/login/logind-user.h +@@ -34,7 +34,11 @@ struct User { + + Session *display; + +- dual_timestamp timestamp; ++ dual_timestamp timestamp; /* When this User object was 'started' the first time */ ++ usec_t last_session_timestamp; /* When the number of sessions of this user went from 1 to 0 the last time */ ++ ++ /* Set up when the last session of the user logs out */ ++ sd_event_source *timer_event_source; + + bool in_gc_queue:1; + +@@ -62,6 +66,7 @@ int user_load(User *u); + int user_kill(User *u, int signo); + int user_check_linger_file(User *u); + void user_elect_display(User *u); ++void user_update_last_session_timer(User *u); + + extern const sd_bus_vtable user_vtable[]; + int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); +diff --git a/src/login/logind.h b/src/login/logind.h +index ae4d74076b..7288dd7445 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -62,6 +62,7 @@ struct Manager { + Hashmap *user_units; + + usec_t inhibit_delay_max; ++ usec_t user_stop_delay; + + /* If an action is currently being executed or is delayed, + * this is != 0 and encodes what is being done */ diff --git a/SOURCES/0632-logind-add-a-RequiresMountsFor-dependency-from-the-s.patch b/SOURCES/0632-logind-add-a-RequiresMountsFor-dependency-from-the-s.patch new file mode 100644 index 0000000..93f6a2c --- /dev/null +++ b/SOURCES/0632-logind-add-a-RequiresMountsFor-dependency-from-the-s.patch @@ -0,0 +1,210 @@ +From e9a187ea6abf1e7034ee3113355b282743a98f39 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 8 Aug 2018 15:27:49 +0200 +Subject: [PATCH] logind: add a RequiresMountsFor= dependency from the session + scope unit to the home directory of the user + +This is useful so that during shutdown scope units are always terminated +before the mounts necessary for the home directory. + +(Ideally we'd also add a similar dependency from the user@.service +instance to the home directory, but this isn't as easy as that service +is defined statically and not dynamically, and hence not easy to modify +dynamically, in particular when it comes to deps) + +(cherry picked from commit d5ac9d060267820aabdf9af509a54a1830b27b7d) + +Related: #1642460 +--- + src/login/logind-core.c | 24 ++++++++++++++++++------ + src/login/logind-dbus.c | 7 +++++++ + src/login/logind-session.c | 1 + + src/login/logind-user.c | 13 ++++++++++++- + src/login/logind-user.h | 3 ++- + src/login/logind.h | 4 ++-- + 6 files changed, 42 insertions(+), 10 deletions(-) + +diff --git a/src/login/logind-core.c b/src/login/logind-core.c +index 678c708df1..0ed812a2c8 100644 +--- a/src/login/logind-core.c ++++ b/src/login/logind-core.c +@@ -128,7 +128,14 @@ int manager_add_session(Manager *m, const char *id, Session **_session) { + return 0; + } + +-int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) { ++int manager_add_user( ++ Manager *m, ++ uid_t uid, ++ gid_t gid, ++ const char *name, ++ const char *home, ++ User **_user) { ++ + User *u; + int r; + +@@ -137,7 +144,7 @@ int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User ** + + u = hashmap_get(m->users, UID_TO_PTR(uid)); + if (!u) { +- r = user_new(&u, m, uid, gid, name); ++ r = user_new(&u, m, uid, gid, name, home); + if (r < 0) + return r; + } +@@ -148,7 +155,12 @@ int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User ** + return 0; + } + +-int manager_add_user_by_name(Manager *m, const char *name, User **_user) { ++int manager_add_user_by_name( ++ Manager *m, ++ const char *name, ++ User **_user) { ++ ++ const char *home = NULL; + uid_t uid; + gid_t gid; + int r; +@@ -156,11 +168,11 @@ int manager_add_user_by_name(Manager *m, const char *name, User **_user) { + assert(m); + assert(name); + +- r = get_user_creds(&name, &uid, &gid, NULL, NULL); ++ r = get_user_creds(&name, &uid, &gid, &home, NULL); + if (r < 0) + return r; + +- return manager_add_user(m, uid, gid, name, _user); ++ return manager_add_user(m, uid, gid, name, home, _user); + } + + int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) { +@@ -173,7 +185,7 @@ int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) { + if (!p) + return errno > 0 ? -errno : -ENOENT; + +- return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user); ++ return manager_add_user(m, uid, p->pw_gid, p->pw_name, p->pw_dir, _user); + } + + int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) { +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index 6586280269..1bb152bc20 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -3313,6 +3313,7 @@ int manager_start_scope( + const char *description, + char **wants, + char **after, ++ const char *requires_mounts_for, + sd_bus_message *more_properties, + sd_bus_error *error, + char **job) { +@@ -3368,6 +3369,12 @@ int manager_start_scope( + return r; + } + ++ if (!empty_or_root(requires_mounts_for)) { ++ r = sd_bus_message_append(m, "(sv)", "RequiresMountsFor", "as", 1, requires_mounts_for); ++ if (r < 0) ++ return r; ++ } ++ + /* Make sure that the session shells are terminated with SIGHUP since bash and friends tend to ignore + * SIGTERM */ + r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true); +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index dd4ac9482a..e4c8bb36f6 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -591,6 +591,7 @@ static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_er + description, + STRV_MAKE(s->user->runtime_dir_service, s->user->service), /* These two have StopWhenUnneeded= set, hence add a dep towards them */ + STRV_MAKE("systemd-logind.service", "systemd-user-sessions.service", s->user->runtime_dir_service, s->user->service), /* And order us after some more */ ++ s->user->home, + properties, + error, + &s->scope_job); +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index f23fcbe674..70f5eb9d59 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -30,7 +30,13 @@ + #include "user-util.h" + #include "util.h" + +-int user_new(User **ret, Manager *m, uid_t uid, gid_t gid, const char *name) { ++int user_new(User **ret, ++ Manager *m, ++ uid_t uid, ++ gid_t gid, ++ const char *name, ++ const char *home) { ++ + _cleanup_(user_freep) User *u = NULL; + char lu[DECIMAL_STR_MAX(uid_t) + 1]; + int r; +@@ -54,6 +60,10 @@ int user_new(User **ret, Manager *m, uid_t uid, gid_t gid, const char *name) { + if (!u->name) + return -ENOMEM; + ++ u->home = strdup(home); ++ if (!u->home) ++ return -ENOMEM; ++ + if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0) + return -ENOMEM; + +@@ -124,6 +134,7 @@ User *user_free(User *u) { + u->runtime_path = mfree(u->runtime_path); + u->state_file = mfree(u->state_file); + u->name = mfree(u->name); ++ u->home = mfree(u->home); + + return mfree(u); + } +diff --git a/src/login/logind-user.h b/src/login/logind-user.h +index e05646adc9..c41973e27d 100644 +--- a/src/login/logind-user.h ++++ b/src/login/logind-user.h +@@ -23,6 +23,7 @@ struct User { + uid_t uid; + gid_t gid; + char *name; ++ char *home; + char *state_file; + char *runtime_path; + +@@ -49,7 +50,7 @@ struct User { + LIST_FIELDS(User, gc_queue); + }; + +-int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name); ++int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name, const char *home); + User *user_free(User *u); + + DEFINE_TRIVIAL_CLEANUP_FUNC(User *, user_free); +diff --git a/src/login/logind.h b/src/login/logind.h +index 7288dd7445..d29b01c75b 100644 +--- a/src/login/logind.h ++++ b/src/login/logind.h +@@ -129,7 +129,7 @@ int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_dev + int manager_add_button(Manager *m, const char *name, Button **_button); + int manager_add_seat(Manager *m, const char *id, Seat **_seat); + int manager_add_session(Manager *m, const char *id, Session **_session); +-int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user); ++int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, const char *home, User **_user); + int manager_add_user_by_name(Manager *m, const char *name, User **_user); + int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user); + int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor); +@@ -162,7 +162,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name + + int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_; + +-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, char **wants, char **after, sd_bus_message *more_properties, sd_bus_error *error, char **job); ++int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, char **wants, char **after, const char *requires_mounts_for, sd_bus_message *more_properties, sd_bus_error *error, char **job); + int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); + int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); + int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error); diff --git a/SOURCES/0633-logind-improve-error-propagation-of-user_check_linge.patch b/SOURCES/0633-logind-improve-error-propagation-of-user_check_linge.patch new file mode 100644 index 0000000..9552207 --- /dev/null +++ b/SOURCES/0633-logind-improve-error-propagation-of-user_check_linge.patch @@ -0,0 +1,39 @@ +From 117ed6bd7aa71fc79599e1d37bdb4a94b3505a38 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 8 Aug 2018 16:03:11 +0200 +Subject: [PATCH] logind: improve error propagation of user_check_linger_file() + +Let's make this a bit prettier, and propagate unexpected access() errors +correctly. + +(The callers of this function will suppress them, but it's nicer of they +do that, rather than us doing that twice in both the callers and the +callees) + +(cherry picked from commit 6996df9b864981980f5b713dc5c7d506a7a4b9bf) + +Related: #1642460 +--- + src/login/logind-user.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 70f5eb9d59..3fd28fc66c 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -532,8 +532,14 @@ int user_check_linger_file(User *u) { + return -ENOMEM; + + p = strjoina("/var/lib/systemd/linger/", cc); ++ if (access(p, F_OK) < 0) { ++ if (errno != ENOENT) ++ return -errno; + +- return access(p, F_OK) >= 0; ++ return false; ++ } ++ ++ return true; + } + + bool user_may_gc(User *u, bool drop_not_started) { diff --git a/SOURCES/0634-logind-automatically-GC-lingering-users-for-who-now-.patch b/SOURCES/0634-logind-automatically-GC-lingering-users-for-who-now-.patch new file mode 100644 index 0000000..e299007 --- /dev/null +++ b/SOURCES/0634-logind-automatically-GC-lingering-users-for-who-now-.patch @@ -0,0 +1,82 @@ +From 89dd5e016a50da082e51129eecb3c5e04b8f0cf5 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 8 Aug 2018 16:04:40 +0200 +Subject: [PATCH] logind: automatically GC lingering users for who now + user@.service (nor slice, not runtime dir service) is running anymore + +This heavily borrows from @intelfx' PR #5546, but watches all three +units that are associated with a user now: the slice, the user@.service +and user-runtime-dir@.service. + +The logic and reasoning behind it is the same though: there's no value +in keeping lingering users around if all their three services are gone. + +Replaces: #5546 +Fixes: #4162 +(cherry picked from commit 4e5b605af202c770dfc8e3562d0f8d0440b2fe14) + +Related: #1642460 +--- + src/login/logind-user.c | 28 +++++++++++++++++++++++++--- + 1 file changed, 25 insertions(+), 3 deletions(-) + +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 3fd28fc66c..bba3158d1a 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -26,6 +26,7 @@ + #include "special.h" + #include "stdio-util.h" + #include "string-table.h" ++#include "strv.h" + #include "unit-name.h" + #include "user-util.h" + #include "util.h" +@@ -542,6 +543,25 @@ int user_check_linger_file(User *u) { + return true; + } + ++static bool user_unit_active(User *u) { ++ const char *i; ++ int r; ++ ++ assert(u->service); ++ assert(u->runtime_dir_service); ++ assert(u->slice); ++ ++ FOREACH_STRING(i, u->service, u->runtime_dir_service, u->slice) { ++ r = manager_unit_is_active(u->manager, i); ++ if (r < 0) ++ log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring", u->service); ++ if (r != 0) ++ return true; ++ } ++ ++ return false; ++} ++ + bool user_may_gc(User *u, bool drop_not_started) { + assert(u); + +@@ -561,8 +581,10 @@ bool user_may_gc(User *u, bool drop_not_started) { + return false; /* Leave it around for a bit longer. */ + } + +- /* Is this a user that shall stay around forever? */ +- if (user_check_linger_file(u) > 0) ++ /* Is this a user that shall stay around forever ("linger")? Before we say "no" to GC'ing for lingering users, let's check ++ * if any of the three units that we maintain for this user is still around. If none of them is, ++ * there's no need to keep this user around even if lingering is enabled. */ ++ if (user_check_linger_file(u) > 0 && user_unit_active(u)) + return false; + + if (u->service_job && manager_job_is_active(u->manager, u->service_job)) +@@ -608,7 +630,7 @@ UserState user_get_state(User *u) { + return all_closing ? USER_CLOSING : USER_ONLINE; + } + +- if (user_check_linger_file(u) > 0) ++ if (user_check_linger_file(u) > 0 && user_unit_active(u)) + return USER_LINGERING; + + return USER_CLOSING; diff --git a/SOURCES/0635-pam_systemd-simplify-code-which-with-we-set-environm.patch b/SOURCES/0635-pam_systemd-simplify-code-which-with-we-set-environm.patch new file mode 100644 index 0000000..9eaff4c --- /dev/null +++ b/SOURCES/0635-pam_systemd-simplify-code-which-with-we-set-environm.patch @@ -0,0 +1,101 @@ +From 96887ddecd1e4c36d8a32411ed515ddaf0f3a0e3 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 20 Jul 2018 11:27:55 +0200 +Subject: [PATCH] pam_systemd: simplify code which with we set environment + variables + +Let's shorten things a bit by splitting out common code in a new +function. + +(cherry picked from commit d6baaa6978d3eb5b8e8497021c4ba576aee936a3) + +Related: #1642460 +--- + src/login/pam_systemd.c | 46 ++++++++++++++++++++++++----------------- + 1 file changed, 27 insertions(+), 19 deletions(-) + +diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c +index 78ddb7d398..b2b62540bb 100644 +--- a/src/login/pam_systemd.c ++++ b/src/login/pam_systemd.c +@@ -301,6 +301,24 @@ static const char* getenv_harder(pam_handle_t *handle, const char *key, const ch + return fallback; + } + ++static int update_environment(pam_handle_t *handle, const char *key, const char *value) { ++ int r; ++ ++ assert(handle); ++ assert(key); ++ ++ /* Updates the environment, but only if there's actually a value set. Also, log about errors */ ++ ++ if (isempty(value)) ++ return PAM_SUCCESS; ++ ++ r = pam_misc_setenv(handle, key, value, 0); ++ if (r != PAM_SUCCESS) ++ pam_syslog(handle, LOG_ERR, "Failed to set environment variable %s.", key); ++ ++ return r; ++} ++ + _public_ PAM_EXTERN int pam_sm_open_session( + pam_handle_t *handle, + int flags, +@@ -555,11 +573,9 @@ _public_ PAM_EXTERN int pam_sm_open_session( + "id=%s object_path=%s runtime_path=%s session_fd=%d seat=%s vtnr=%u original_uid=%u", + id, object_path, runtime_path, session_fd, seat, vtnr, original_uid); + +- r = pam_misc_setenv(handle, "XDG_SESSION_ID", id, 0); +- if (r != PAM_SUCCESS) { +- pam_syslog(handle, LOG_ERR, "Failed to set session id."); ++ r = update_environment(handle, "XDG_SESSION_ID", id); ++ if (r != PAM_SUCCESS) + return r; +- } + + if (original_uid == pw->pw_uid) { + /* Don't set $XDG_RUNTIME_DIR if the user we now +@@ -568,34 +584,26 @@ _public_ PAM_EXTERN int pam_sm_open_session( + * in privileged apps clobbering the runtime directory + * unnecessarily. */ + +- r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", runtime_path, 0); +- if (r != PAM_SUCCESS) { +- pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); ++ r = update_environment(handle, "XDG_RUNTIME_DIR", runtime_path); ++ if (r != PAM_SUCCESS) + return r; +- } + + r = export_legacy_dbus_address(handle, pw->pw_uid, runtime_path); + if (r != PAM_SUCCESS) + return r; + } + +- if (!isempty(seat)) { +- r = pam_misc_setenv(handle, "XDG_SEAT", seat, 0); +- if (r != PAM_SUCCESS) { +- pam_syslog(handle, LOG_ERR, "Failed to set seat."); +- return r; +- } +- } ++ r = update_environment(handle, "XDG_SEAT", seat); ++ if (r != PAM_SUCCESS) ++ return r; + + if (vtnr > 0) { + char buf[DECIMAL_STR_MAX(vtnr)]; + sprintf(buf, "%u", vtnr); + +- r = pam_misc_setenv(handle, "XDG_VTNR", buf, 0); +- if (r != PAM_SUCCESS) { +- pam_syslog(handle, LOG_ERR, "Failed to set virtual terminal number."); ++ r = update_environment(handle, "XDG_VTNR", buf); ++ if (r != PAM_SUCCESS) + return r; +- } + } + + r = pam_set_data(handle, "systemd.existing", INT_TO_PTR(!!existing), NULL); diff --git a/SOURCES/0636-logind-validate-run-user-1000-before-we-set-it.patch b/SOURCES/0636-logind-validate-run-user-1000-before-we-set-it.patch new file mode 100644 index 0000000..e485042 --- /dev/null +++ b/SOURCES/0636-logind-validate-run-user-1000-before-we-set-it.patch @@ -0,0 +1,89 @@ +From c8b74ac5cf508c7bcec92d197880043af1d2bad7 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 9 Oct 2018 22:23:41 +0200 +Subject: [PATCH] logind: validate /run/user/1000 before we set it + +Let's be safe than sorry, in particular as logind doesn't set it up +anymore, but user-runtime-dir@.service does, and logind doesn't really +track success of that. + +(cherry picked from commit b92171124819305985ed292cc472f6668a027425) + +Related: #1642460 +--- + src/login/pam_systemd.c | 48 +++++++++++++++++++++++++++++++++++------ + 1 file changed, 41 insertions(+), 7 deletions(-) + +diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c +index b2b62540bb..64e1b4d1bf 100644 +--- a/src/login/pam_systemd.c ++++ b/src/login/pam_systemd.c +@@ -319,6 +319,36 @@ static int update_environment(pam_handle_t *handle, const char *key, const char + return r; + } + ++static bool validate_runtime_directory(pam_handle_t *handle, const char *path, uid_t uid) { ++ struct stat st; ++ ++ assert(path); ++ ++ /* Just some extra paranoia: let's not set $XDG_RUNTIME_DIR if the directory we'd set it to isn't actually set ++ * up properly for us. */ ++ ++ if (lstat(path, &st) < 0) { ++ pam_syslog(handle, LOG_ERR, "Failed to stat() runtime directory '%s': %s", path, strerror(errno)); ++ goto fail; ++ } ++ ++ if (!S_ISDIR(st.st_mode)) { ++ pam_syslog(handle, LOG_ERR, "Runtime directory '%s' is not actually a directory.", path); ++ goto fail; ++ } ++ ++ if (st.st_uid != uid) { ++ pam_syslog(handle, LOG_ERR, "Runtime directory '%s' is not owned by UID " UID_FMT ", as it should.", path, uid); ++ goto fail; ++ } ++ ++ return true; ++ ++fail: ++ pam_syslog(handle, LOG_WARNING, "Not setting $XDG_RUNTIME_DIR, as the directory is not in order."); ++ return false; ++} ++ + _public_ PAM_EXTERN int pam_sm_open_session( + pam_handle_t *handle, + int flags, +@@ -377,10 +407,12 @@ _public_ PAM_EXTERN int pam_sm_open_session( + if (asprintf(&rt, "/run/user/"UID_FMT, pw->pw_uid) < 0) + return PAM_BUF_ERR; + +- r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0); +- if (r != PAM_SUCCESS) { +- pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); +- return r; ++ if (validate_runtime_directory(handle, rt, pw->pw_uid)) { ++ r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0); ++ if (r != PAM_SUCCESS) { ++ pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); ++ return r; ++ } + } + + r = export_legacy_dbus_address(handle, pw->pw_uid, rt); +@@ -584,9 +616,11 @@ _public_ PAM_EXTERN int pam_sm_open_session( + * in privileged apps clobbering the runtime directory + * unnecessarily. */ + +- r = update_environment(handle, "XDG_RUNTIME_DIR", runtime_path); +- if (r != PAM_SUCCESS) +- return r; ++ if (validate_runtime_directory(handle, runtime_path, pw->pw_uid)) { ++ r = update_environment(handle, "XDG_RUNTIME_DIR", runtime_path); ++ if (r != PAM_SUCCESS) ++ return r; ++ } + + r = export_legacy_dbus_address(handle, pw->pw_uid, runtime_path); + if (r != PAM_SUCCESS) diff --git a/SOURCES/triggers.systemd b/SOURCES/triggers.systemd index 04abfd1..90906e3 100644 --- a/SOURCES/triggers.systemd +++ b/SOURCES/triggers.systemd @@ -105,5 +105,7 @@ fi # This script will automatically apply binfmt rules if files have been # installed or updated in /usr/lib/binfmt.d. if test -d /run/systemd/system; then - /usr/lib/systemd/systemd-binfmt + # systemd-binfmt might fail if binfmt_misc kernel module is not loaded + # during install + /usr/lib/systemd/systemd-binfmt || : fi diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index a3c4fe1..bb99bcf 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -13,7 +13,7 @@ Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd Version: 239 -Release: 44%{?dist} +Release: 50%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -593,6 +593,99 @@ Patch0540: 0540-test-udev-test.pl-generator-for-large-list-of-block-.patch Patch0541: 0541-test-udev-test.pl-suppress-umount-error-message-at-s.patch Patch0542: 0542-test-udev_test.pl-add-expected-good-count.patch Patch0543: 0543-test-udev-test-gracefully-exit-when-imports-fail.patch +Patch0544: 0544-Revert-test-add-test-cases-for-empty-string-match-an.patch +Patch0545: 0545-test-sys-script.py-add-missing-DEVNAME-entries-to-ue.patch +Patch0546: 0546-sd-event-split-out-helper-functions-for-reshuffling-.patch +Patch0547: 0547-sd-event-split-out-enable-and-disable-codepaths-from.patch +Patch0548: 0548-sd-event-mention-that-two-debug-logged-events-are-ig.patch +Patch0549: 0549-sd-event-split-clock-data-allocation-out-of-sd_event.patch +Patch0550: 0550-sd-event-split-out-code-to-add-remove-timer-event-so.patch +Patch0551: 0551-sd-event-fix-delays-assert-brain-o-17790.patch +Patch0552: 0552-sd-event-let-s-suffix-last_run-last_log-with-_usec.patch +Patch0553: 0553-sd-event-refuse-running-default-event-loops-in-any-o.patch +Patch0554: 0554-sd-event-ref-event-loop-while-in-sd_event_prepare-ot.patch +Patch0555: 0555-sd-event-follow-coding-style-with-naming-return-para.patch +Patch0556: 0556-sd-event-remove-earliest_index-latest_index-into-com.patch +Patch0557: 0557-sd-event-update-state-at-the-end-in-event_source_ena.patch +Patch0558: 0558-sd-event-increase-n_enabled_child_sources-just-once.patch +Patch0559: 0559-sd-event-add-ability-to-ratelimit-event-sources.patch +Patch0560: 0560-test-add-ratelimiting-test.patch +Patch0561: 0561-core-prevent-excessive-proc-self-mountinfo-parsing.patch +Patch0562: 0562-udev-run-link_update-with-increased-retry-count-in-s.patch +Patch0563: 0563-pam-systemd-use-secure_getenv-rather-than-getenv.patch +Patch0564: 0564-Revert-udev-run-link_update-with-increased-retry-cou.patch +Patch0565: 0565-Revert-udev-make-algorithm-that-selects-highest-prio.patch +Patch0566: 0566-test-udev-test.pl-drop-test-cases-that-add-mutliple-.patch +Patch0567: 0567-cgroup-Also-set-io.bfq.weight.patch +Patch0568: 0568-seccomp-allow-turning-off-of-seccomp-filtering-via-e.patch +Patch0569: 0569-meson-remove-strange-dep-that-causes-meson-to-enter-.patch +Patch0570: 0570-copy-handle-copy_file_range-weirdness-on-procfs-sysf.patch +Patch0571: 0571-core-Hide-Deactivated-successfully-message.patch +Patch0572: 0572-util-rework-in_initrd-to-make-use-of-path_is_tempora.patch +Patch0573: 0573-initrd-extend-SYSTEMD_IN_INITRD-to-accept-non-ramfs-.patch +Patch0574: 0574-initrd-do-a-debug-log-if-failed-to-detect-rootfs-typ.patch +Patch0575: 0575-initrd-do-a-debug-log-if-etc-initrd-release-doesn-t-.patch +Patch0576: 0576-units-assign-user-runtime-dir-.service-to-user-i.sli.patch +Patch0577: 0577-units-order-user-runtime-dir-.service-after-systemd-.patch +Patch0578: 0578-units-make-sure-user-runtime-dir-.service-is-Type-on.patch +Patch0579: 0579-user-runtime-dir-downgrade-a-few-log-messages-to-LOG.patch +Patch0580: 0580-shared-install-Preserve-escape-characters-for-escape.patch +Patch0581: 0581-basic-virt-Detect-PowerVM-hypervisor.patch +Patch0582: 0582-man-document-differences-in-clean-exit-status-for-Ty.patch +Patch0583: 0583-busctl-add-a-timestamp-to-the-output-of-the-busctl-m.patch +Patch0584: 0584-basic-cap-list-parse-print-numerical-capabilities.patch +Patch0585: 0585-shared-mount-util-convert-to-libmount.patch +Patch0586: 0586-mount-util-bind_remount-avoid-calling-statvfs.patch +Patch0587: 0587-mount-util-use-UMOUNT_NOFOLLOW-in-recursive-umounter.patch +Patch0588: 0588-test-install-root-create-referenced-targets.patch +Patch0589: 0589-install-warn-if-WantedBy-targets-don-t-exist.patch +Patch0590: 0590-test-install-root-add-test-for-unknown-WantedBy-targ.patch +Patch0591: 0591-ceph-is-a-network-filesystem.patch +Patch0592: 0592-sysctl-set-kernel.core_pipe_limit-16.patch +Patch0593: 0593-core-don-t-drop-timer-expired-but-not-yet-processed-.patch +Patch0594: 0594-core-Detect-initial-timer-state-from-serialized-data.patch +Patch0595: 0595-rc-local-order-after-network-online.target.patch +Patch0596: 0596-set-core-ulimit-to-0-like-on-RHEL-7.patch +Patch0597: 0597-test-mountpointutil-util-do-not-assert-in-test_mnt_i.patch +Patch0598: 0598-remove-a-left-over-break.patch +Patch0599: 0599-basic-unit-name-do-not-use-strdupa-on-a-path.patch +Patch0600: 0600-sd-event-change-ordering-of-pending-ratelimited-even.patch +Patch0601: 0601-sd-event-drop-unnecessary-else.patch +Patch0602: 0602-sd-event-use-CMP-macro.patch +Patch0603: 0603-sd-event-use-usec_add.patch +Patch0604: 0604-sd-event-make-event_source_time_prioq_reshuffle-acce.patch +Patch0605: 0605-sd-event-always-reshuffle-time-prioq-on-changing-onl.patch +Patch0606: 0606-ci-run-unit-tests-on-z-stream-branches-as-well.patch +Patch0607: 0607-ci-drop-forgotten-Travis-references.patch +Patch0608: 0608-ci-run-unit-tests-on-CentOS-8-Stream-as-well.patch +Patch0609: 0609-ci-add-missing-test-dependencies.patch +Patch0610: 0610-meson-bump-timeout-for-test-udev-to-180s.patch +Patch0611: 0611-Added-option-check-inhibitors-for-non-tty-usage.patch +Patch0612: 0612-logind-Introduce-RebootWithFlags-and-others.patch +Patch0613: 0613-logind-add-WithFlags-methods-to-policy.patch +Patch0614: 0614-logind-simplify-flags-handling-a-bit.patch +Patch0615: 0615-Update-link-to-RHEL-documentation.patch +Patch0616: 0616-Set-default-core-ulimit-to-0-but-keep-the-hard-limit.patch +Patch0617: 0617-shared-seccomp-util-address-family-filtering-is-brok.patch +Patch0618: 0618-logind-rework-Seat-Session-User-object-allocation-an.patch +Patch0619: 0619-logind-fix-serialization-deserialization-of-user-s-d.patch +Patch0620: 0620-logind-turn-of-stdio-locking-when-writing-session-fi.patch +Patch0621: 0621-units-set-StopWhenUnneeded-for-the-user-slice-units-.patch +Patch0622: 0622-units-improve-Description-string-a-bit.patch +Patch0623: 0623-logind-improve-logging-in-manager_connect_console.patch +Patch0624: 0624-logind-save-restore-User-object-s-stopping-field-dur.patch +Patch0625: 0625-logind-correct-bad-clean-up-path.patch +Patch0626: 0626-logind-fix-bad-error-propagation.patch +Patch0627: 0627-logind-never-elect-a-session-that-is-stopping-as-dis.patch +Patch0628: 0628-logind-introduce-little-helper-that-checks-whether-a.patch +Patch0629: 0629-logind-propagate-session-stop-errors.patch +Patch0630: 0630-logind-rework-how-we-manage-the-slice-and-user-runti.patch +Patch0631: 0631-logind-optionally-keep-the-user-.service-instance-fo.patch +Patch0632: 0632-logind-add-a-RequiresMountsFor-dependency-from-the-s.patch +Patch0633: 0633-logind-improve-error-propagation-of-user_check_linge.patch +Patch0634: 0634-logind-automatically-GC-lingering-users-for-who-now-.patch +Patch0635: 0635-pam_systemd-simplify-code-which-with-we-set-environm.patch +Patch0636: 0636-logind-validate-run-user-1000-before-we-set-it.patch %ifarch %{ix86} x86_64 aarch64 @@ -625,7 +718,6 @@ BuildRequires: libgpg-error-devel BuildRequires: gnutls-devel BuildRequires: libmicrohttpd-devel BuildRequires: libxkbcommon-devel -BuildRequires: iptables-devel BuildRequires: libxslt BuildRequires: docbook-style-xsl BuildRequires: pkgconfig @@ -647,6 +739,8 @@ Requires(post): coreutils Requires(post): sed Requires(post): acl Requires(post): grep +# systemd-machine-id-setup requires libssl +Requires(post): openssl-libs Requires(pre): coreutils Requires(pre): /usr/bin/getent Requires(pre): /usr/sbin/groupadd @@ -833,7 +927,7 @@ CONFIGURE_OPTS=( -Dgnutls=true -Dmicrohttpd=true -Dlibidn2=true - -Dlibiptc=true + -Dlibiptc=false -Dlibcurl=true -Defi=true -Dgnu-efi=%{?have_gnu_efi:true}%{?!have_gnu_efi:false} @@ -1053,16 +1147,14 @@ if [ -e /etc/fstab ]; then sed -i.rpm.bak -r '/^devpts\s+\/dev\/pts\s+devpts\s+defaults\s+/d; /^tmpfs\s+\/dev\/shm\s+tmpfs\s+defaults\s+/d; /^sysfs\s+\/sys\s+sysfs\s+defaults\s+/d; /^proc\s+\/proc\s+proc\s+defaults\s+/d' /etc/fstab || : fi -# Services we install by default, and which are controlled by presets. +# We reset the enablement of all services upon initial installation +# https://bugzilla.redhat.com/show_bug.cgi?id=1118740#c23 +# This will fix up enablement of any preset services that got installed +# before systemd due to rpm ordering problems: +# Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=1647172 +# RHEL: https://bugzilla.redhat.com/show_bug.cgi?id=1783263 if [ $1 -eq 1 ] ; then - systemctl preset --quiet \ - remote-fs.target \ - getty@.service \ - serial-getty@.service \ - console-getty.service \ - debug-shell.service \ - systemd-resolved.service \ - >/dev/null || : + systemctl preset-all &>/dev/null || : fi # remove obsolete systemd-readahead file @@ -1221,6 +1313,115 @@ fi %files tests -f .file-list-tests %changelog +* Fri Aug 27 2021 systemd maintenance team - 239-50 +- Added option --check-inhibitors for non-tty usage (#1269726) +- logind: Introduce RebootWithFlags and others (#1269726) +- logind: add …WithFlags methods to policy (#1269726) +- logind: simplify flags handling a bit (#1269726) +- Update link to RHEL documentation (#1982584) +- Set default core ulimit to 0, but keep the hard limit ulimited (#1905582) +- shared/seccomp-util: address family filtering is broken on ppc (#1982650) +- logind: rework Seat/Session/User object allocation and freeing a bit (#1642460) +- logind: fix serialization/deserialization of user's "display session" (#1642460) +- logind: turn of stdio locking when writing session files too (#1642460) +- units: set StopWhenUnneeded= for the user slice units too (#1642460) +- units: improve Description= string a bit (#1642460) +- logind: improve logging in manager_connect_console() (#1642460) +- logind: save/restore User object's "stopping" field during restarts (#1642460) +- logind: correct bad clean-up path (#1642460) +- logind: fix bad error propagation (#1642460) +- logind: never elect a session that is stopping as display (#1642460) +- logind: introduce little helper that checks whether a session is ready (#1642460) +- logind: propagate session stop errors (#1642460) +- logind: rework how we manage the slice and user-runtime-dir@.service unit for each user (#1642460) +- logind: optionally, keep the user@.service instance for eached logged in user around for a while (#1642460) +- logind: add a RequiresMountsFor= dependency from the session scope unit to the home directory of the user (#1642460) +- logind: improve error propagation of user_check_linger_file() (#1642460) +- logind: automatically GC lingering users for who now user@.service (nor slice, not runtime dir service) is running anymore (#1642460) +- pam_systemd: simplify code which with we set environment variables (#1642460) +- logind: validate /run/user/1000 before we set it (#1642460) + +* Fri Jul 23 2021 systemd maintenance team - 239-49 +- remove a left-over break (#1970860) +- basic/unit-name: do not use strdupa() on a path (#1974700) +- sd-event: change ordering of pending/ratelimited events (#1968528) +- sd-event: drop unnecessary "else" (#1968528) +- sd-event: use CMP() macro (#1968528) +- sd-event: use usec_add() (#1968528) +- sd-event: make event_source_time_prioq_reshuffle() accept all event source type (#1968528) +- sd-event: always reshuffle time prioq on changing online/offline state (#1968528) +- ci: run unit tests on z-stream branches as well (#1970860) +- ci: drop forgotten Travis references (#1934504) +- ci: run unit tests on CentOS 8 Stream as well (#1934504) +- ci: add missing test dependencies (#1934504) +- meson: bump timeout for test-udev to 180s (#1934504) + +* Thu Jun 24 2021 systemd maintenance team - 239-48 +- cgroup: Also set io.bfq.weight (#1927290) +- seccomp: allow turning off of seccomp filtering via env var (#1916835) +- meson: remove strange dep that causes meson to enter infinite loop (#1970860) +- copy: handle copy_file_range() weirdness on procfs/sysfs (#1970860) +- core: Hide "Deactivated successfully" message (#1954802) +- util: rework in_initrd() to make use of path_is_temporary_fs() (#1959339) +- initrd: extend SYSTEMD_IN_INITRD to accept non-ramfs rootfs (#1959339) +- initrd: do a debug log if failed to detect rootfs type (#1959339) +- initrd: do a debug log if /etc/initrd-release doesn't take effect (#1959339) +- units: assign user-runtime-dir@.service to user-%i.slice (#1946453) +- units: order user-runtime-dir@.service after systemd-user-sessions.service (#1946453) +- units: make sure user-runtime-dir@.service is Type=oneshot (#1946453) +- user-runtime-dir: downgrade a few log messages to LOG_DEBUG that we ignore (#1946453) +- shared/install: Preserve escape characters for escaped unit names (#1952686) +- basic/virt: Detect PowerVM hypervisor (#1937989) +- man: document differences in clean exit status for Type=oneshot (#1940078) +- busctl: add a timestamp to the output of the busctl monitor command (#1909214) +- basic/cap-list: parse/print numerical capabilities (#1946943) +- shared/mount-util: convert to libmount (#1885143) +- mount-util: bind_remount: avoid calling statvfs (#1885143) +- mount-util: use UMOUNT_NOFOLLOW in recursive umounter (#1885143) +- test-install-root: create referenced targets (#1835351) +- install: warn if WantedBy targets don't exist (#1835351) +- test-install-root: add test for unknown WantedBy= target (#1835351) +- ceph is a network filesystem (#1952013) +- sysctl: set kernel.core_pipe_limit=16 (#1949729) +- core: don't drop timer expired but not yet processed when system date is changed (#1899402) +- core: Detect initial timer state from serialized data (#1899402) +- rc-local: order after network-online.target (#1934028) +- set core ulimit to 0 like on RHEL-7 (#1905582) +- test-mountpointutil-util: do not assert in test_mnt_id() (#1910425) + +* Fri Jun 04 2021 Jan Macku - 239-47 +- systemd-binfmt: Add safeguard in triggers (#1787144) +- spec: Requires(post) openssl-libs to fix missing /etc/machine-id (#1947438) +- spec: Go back to using systemctl preset-all in post (#1783263, #1647172, #1118740) +- spec: Disable libiptc support (#1817265) + +* Wed May 19 2021 systemd maintenance team - 239-46 +- Revert "udev: run link_update() with increased retry count in second invocation" (#1942299) +- Revert "udev: make algorithm that selects highest priority devlink less susceptible to race conditions" (#1942299) +- test/udev-test.pl: drop test cases that add mutliple devices (#1942299) + +* Thu Mar 11 2021 systemd maintenance team - 239-45 +- Revert "test: add test cases for empty string match" and "test: add test case for multi matches when use ||" (#1935124) +- test/sys-script.py: add missing DEVNAME entries to uevents (#1935124) +- sd-event: split out helper functions for reshuffling prioqs (#1937315) +- sd-event: split out enable and disable codepaths from sd_event_source_set_enabled() (#1937315) +- sd-event: mention that two debug logged events are ignored (#1937315) +- sd-event: split clock data allocation out of sd_event_add_time() (#1937315) +- sd-event: split out code to add/remove timer event sources to earliest/latest prioq (#1937315) +- sd-event: fix delays assert brain-o (#17790) (#1937315) +- sd-event: let's suffix last_run/last_log with "_usec" (#1937315) +- sd-event: refuse running default event loops in any other thread than the one they are default for (#1937315) +- sd-event: ref event loop while in sd_event_prepare() ot sd_event_run() (#1937315) +- sd-event: follow coding style with naming return parameter (#1937315) +- sd-event: remove earliest_index/latest_index into common part of event source objects (#1937315) +- sd-event: update state at the end in event_source_enable (#1937315) +- sd-event: increase n_enabled_child_sources just once (#1937315) +- sd-event: add ability to ratelimit event sources (#1937315) +- test: add ratelimiting test (#1937315) +- core: prevent excessive /proc/self/mountinfo parsing (#1937315) +- udev: run link_update() with increased retry count in second invocation (#1935124) +- pam-systemd: use secure_getenv() rather than getenv() (#1936866) + * Thu Jan 28 2021 systemd maintenance team - 239-44 - ci: PowerTools repo was renamed to powertools in RHEL 8.3 (#1871827) - ci: use quay.io instead of Docker Hub to avoid rate limits (#1871827)