summaryrefslogtreecommitdiffstats
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/debian/Add-support-for-TuxOnIce-hibernation.patch30
-rw-r--r--debian/patches/debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch21
-rw-r--r--debian/patches/debian/Don-t-enable-audit-by-default.patch53
-rw-r--r--debian/patches/debian/Downgrade-a-couple-of-warnings-to-debug.patch74
-rw-r--r--debian/patches/debian/Let-graphical-session-pre.target-be-manually-started.patch22
-rw-r--r--debian/patches/debian/Make-run-lock-tmpfs-an-API-fs.patch42
-rw-r--r--debian/patches/debian/Move-sysusers.d-sysctl.d-binfmt.d-modules-load.d-back-to-.patch68
-rw-r--r--debian/patches/debian/Only-start-logind-if-dbus-is-installed.patch28
-rw-r--r--debian/patches/debian/Re-enable-journal-forwarding-to-syslog.patch56
-rw-r--r--debian/patches/debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch37
-rw-r--r--debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch71
-rw-r--r--debian/patches/debian/Skip-filesystem-check-if-already-done-by-the-initram.patch57
-rw-r--r--debian/patches/debian/Skip-flaky-test_resolved_domain_restricted_dns-in-network.patch24
-rw-r--r--debian/patches/debian/Use-Debian-specific-config-files.patch363
-rw-r--r--debian/patches/debian/deny-list-upstream-test-02-ppc64el.patch17
-rw-r--r--debian/patches/debian/deny-list-upstream-test-25.patch17
-rw-r--r--debian/patches/debian/fsckd-daemon-for-inter-fsckd-communication.patch1068
-rw-r--r--debian/patches/debian/systemctl-do-not-shutdown-immediately-on-scheduled-shutdo.patch34
-rw-r--r--debian/patches/debian/udev-drop-SystemCallArchitectures-native-from-systemd-ude.patch25
-rw-r--r--debian/patches/p11kit-switch-to-dlopen.patch743
-rw-r--r--debian/patches/series20
21 files changed, 2870 insertions, 0 deletions
diff --git a/debian/patches/debian/Add-support-for-TuxOnIce-hibernation.patch b/debian/patches/debian/Add-support-for-TuxOnIce-hibernation.patch
new file mode 100644
index 0000000..887b6a1
--- /dev/null
+++ b/debian/patches/debian/Add-support-for-TuxOnIce-hibernation.patch
@@ -0,0 +1,30 @@
+From: Julien Muchembled <jm@jmuchemb.eu>
+Date: Tue, 29 Apr 2014 11:40:50 +0200
+Subject: Add support for TuxOnIce hibernation
+
+systemd does not support non-mainline kernel features so upstream rejected this
+patch.
+It is however required for systemd integration by tuxonice-userui package.
+
+Forwarded: http://lists.freedesktop.org/archives/systemd-devel/2014-April/018960.html
+---
+ src/shared/sleep-config.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
+index 69b3e35..5664752 100644
+--- a/src/shared/sleep-config.c
++++ b/src/shared/sleep-config.c
+@@ -973,6 +973,12 @@ static bool enough_swap_for_hibernation(void) {
+ if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
+ return true;
+
++ /* TuxOnIce is an alternate implementation for hibernation.
++ * It can be configured to compress the image to a file or an inactive
++ * swap partition, so there's nothing more we can do here. */
++ if (access("/sys/power/tuxonice", F_OK) == 0)
++ return true;
++
+ r = find_hibernate_location(&hibernate_location);
+ if (r < 0)
+ return false;
diff --git a/debian/patches/debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch b/debian/patches/debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch
new file mode 100644
index 0000000..d99ea42
--- /dev/null
+++ b/debian/patches/debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch
@@ -0,0 +1,21 @@
+From: Tollef Fog Heen <tfheen@err.no>
+Date: Tue, 5 Jun 2012 20:59:36 +0200
+Subject: Bring tmpfiles.d/tmp.conf in line with Debian defaults
+
+Closes: #675422
+---
+ tmpfiles.d/tmp.conf | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tmpfiles.d/tmp.conf b/tmpfiles.d/tmp.conf
+index fe5225d..39cb5cc 100644
+--- a/tmpfiles.d/tmp.conf
++++ b/tmpfiles.d/tmp.conf
+@@ -8,5 +8,5 @@
+ # See tmpfiles.d(5) for details
+
+ # Clear tmp directories separately, to make them easier to override
+-q /tmp 1777 root root 10d
+-q /var/tmp 1777 root root 30d
++D /tmp 1777 root root -
++#q /var/tmp 1777 root root 30d
diff --git a/debian/patches/debian/Don-t-enable-audit-by-default.patch b/debian/patches/debian/Don-t-enable-audit-by-default.patch
new file mode 100644
index 0000000..67f2b46
--- /dev/null
+++ b/debian/patches/debian/Don-t-enable-audit-by-default.patch
@@ -0,0 +1,53 @@
+From: Martin Pitt <martin.pitt@ubuntu.com>
+Date: Sun, 28 Dec 2014 12:49:35 +0100
+Subject: Don't enable audit by default
+
+It causes flooding of dmesg and syslog, suppressing actually important
+messages.
+
+Don't enable it for now, until a better solution is found:
+http://lists.freedesktop.org/archives/systemd-devel/2014-December/026591.html
+
+Bug-Debian: https://bugs.debian.org/773528
+---
+ man/journald.conf.xml | 2 +-
+ src/journal/journald-server.c | 2 +-
+ src/journal/journald.conf | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/man/journald.conf.xml b/man/journald.conf.xml
+index 160544a..7e6f175 100644
+--- a/man/journald.conf.xml
++++ b/man/journald.conf.xml
+@@ -438,7 +438,7 @@
+ <command>systemd-journald</command> collects generated audit records, it just controls whether it
+ tells the kernel to generate them. This means if another tool turns on auditing even if
+ <command>systemd-journald</command> left it off, it will still collect the generated
+- messages. Defaults to on.</para></listitem>
++ messages. Defaults to off.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
+index a78e2c0..efeb50c 100644
+--- a/src/journal/journald-server.c
++++ b/src/journal/journald-server.c
+@@ -2279,7 +2279,7 @@ int server_init(Server *s, const char *namespace) {
+ .compress.threshold_bytes = UINT64_MAX,
+ .seal = true,
+
+- .set_audit = true,
++ .set_audit = false,
+
+ .watchdog_usec = USEC_INFINITY,
+
+diff --git a/src/journal/journald.conf b/src/journal/journald.conf
+index 64f4d4b..a690681 100644
+--- a/src/journal/journald.conf
++++ b/src/journal/journald.conf
+@@ -44,4 +44,4 @@
+ #MaxLevelWall=emerg
+ #LineMax=48K
+ #ReadKMsg=yes
+-#Audit=yes
++#Audit=no
diff --git a/debian/patches/debian/Downgrade-a-couple-of-warnings-to-debug.patch b/debian/patches/debian/Downgrade-a-couple-of-warnings-to-debug.patch
new file mode 100644
index 0000000..1b3ba16
--- /dev/null
+++ b/debian/patches/debian/Downgrade-a-couple-of-warnings-to-debug.patch
@@ -0,0 +1,74 @@
+From: Michael Biebl <biebl@debian.org>
+Date: Tue, 16 Feb 2021 00:18:50 +0100
+Subject: Downgrade a couple of warnings to debug
+
+If a package still ships only a SysV init script or if a service file or
+tmpfile uses /var/run, downgrade those messages to debug. We can use
+lintian to detect those issues.
+For service files and tmpfiles in /etc, keep the warning, as those files
+are typically added locally and aren't checked by lintian.
+
+Closes: #981407
+---
+ src/core/load-fragment.c | 4 +++-
+ src/sysv-generator/sysv-generator.c | 2 +-
+ src/tmpfiles/tmpfiles.c | 4 +++-
+ 3 files changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
+index 1001faa..555492e 100644
+--- a/src/core/load-fragment.c
++++ b/src/core/load-fragment.c
+@@ -543,6 +543,7 @@ static int patch_var_run(
+
+ const char *e;
+ char *z;
++ int log_level;
+
+ e = path_startswith(*path, "/var/run/");
+ if (!e)
+@@ -552,7 +553,8 @@ static int patch_var_run(
+ if (!z)
+ return log_oom();
+
+- log_syntax(unit, LOG_NOTICE, filename, line, 0,
++ log_level = path_startswith(filename, "/etc") ? LOG_NOTICE : LOG_DEBUG;
++ log_syntax(unit, log_level, filename, line, 0,
+ "%s= references a path below legacy directory /var/run/, updating %s → %s; "
+ "please update the unit file accordingly.", lvalue, *path, z);
+
+diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
+index 3c5df6c..24eff86 100644
+--- a/src/sysv-generator/sysv-generator.c
++++ b/src/sysv-generator/sysv-generator.c
+@@ -761,7 +761,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
+ if (!fpath)
+ return log_oom();
+
+- log_warning("SysV service '%s' lacks a native systemd unit file. "
++ log_debug("SysV service '%s' lacks a native systemd unit file. "
+ "Automatically generating a unit file for compatibility. "
+ "Please update package to include a native systemd unit file, in order to make it more safe and robust.", fpath);
+
+diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
+index 9c3d994..15180a5 100644
+--- a/src/tmpfiles/tmpfiles.c
++++ b/src/tmpfiles/tmpfiles.c
+@@ -2991,6 +2991,7 @@ static int specifier_expansion_from_arg(const Specifier *specifier_table, Item *
+ static int patch_var_run(const char *fname, unsigned line, char **path) {
+ const char *k;
+ char *n;
++ int log_level;
+
+ assert(path);
+ assert(*path);
+@@ -3016,7 +3017,8 @@ static int patch_var_run(const char *fname, unsigned line, char **path) {
+ /* Also log about this briefly. We do so at LOG_NOTICE level, as we fixed up the situation automatically, hence
+ * there's no immediate need for action by the user. However, in the interest of making things less confusing
+ * to the user, let's still inform the user that these snippets should really be updated. */
+- log_syntax(NULL, LOG_NOTICE, fname, line, 0,
++ log_level = path_startswith(fname, "/etc") ? LOG_NOTICE : LOG_DEBUG;
++ log_syntax(NULL, log_level, fname, line, 0,
+ "Line references path below legacy directory /var/run/, updating %s → %s; please update the tmpfiles.d/ drop-in file accordingly.",
+ *path, n);
+
diff --git a/debian/patches/debian/Let-graphical-session-pre.target-be-manually-started.patch b/debian/patches/debian/Let-graphical-session-pre.target-be-manually-started.patch
new file mode 100644
index 0000000..cf8db56
--- /dev/null
+++ b/debian/patches/debian/Let-graphical-session-pre.target-be-manually-started.patch
@@ -0,0 +1,22 @@
+From: Iain Lane <iain@orangesquash.org.uk>
+Date: Mon, 22 Aug 2016 07:03:27 +0200
+Subject: Let graphical-session-pre.target be manually started
+
+This is needed until https://github.com/systemd/systemd/issues/3750 is fixed.
+
+Forwarded: not-needed
+Bug-Ubuntu: https://launchpad.net/bugs/1615341
+---
+ units/user/graphical-session-pre.target | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/units/user/graphical-session-pre.target b/units/user/graphical-session-pre.target
+index 4b9e3dc..dffaf85 100644
+--- a/units/user/graphical-session-pre.target
++++ b/units/user/graphical-session-pre.target
+@@ -12,5 +12,4 @@ Description=Session services which should run early before the graphical session
+ Documentation=man:systemd.special(7)
+ Requires=basic.target
+ Before=graphical-session.target
+-RefuseManualStart=yes
+ StopWhenUnneeded=yes
diff --git a/debian/patches/debian/Make-run-lock-tmpfs-an-API-fs.patch b/debian/patches/debian/Make-run-lock-tmpfs-an-API-fs.patch
new file mode 100644
index 0000000..574f44d
--- /dev/null
+++ b/debian/patches/debian/Make-run-lock-tmpfs-an-API-fs.patch
@@ -0,0 +1,42 @@
+From: Michael Biebl <biebl@debian.org>
+Date: Fri, 5 Sep 2014 01:15:16 +0200
+Subject: Make /run/lock tmpfs an API fs
+
+The /run/lock directory is world-writable in Debian due to historic
+reasons. To avoid user processes filling up /run, we mount a separate
+tmpfs for /run/lock. As this directory needs to be available during
+early boot, we make it an API fs.
+
+Drop it from tmpfiles.d/legacy.conf to not clobber the permissions.
+
+Closes: #751392
+---
+ src/shared/mount-setup.c | 2 ++
+ tmpfiles.d/legacy.conf.in | 1 -
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c
+index 6882b62..c54e632 100644
+--- a/src/shared/mount-setup.c
++++ b/src/shared/mount-setup.c
+@@ -86,6 +86,8 @@ static const MountPoint mount_table[] = {
+ #endif
+ { "tmpfs", "/run", "tmpfs", "mode=755" TMPFS_LIMITS_RUN, MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
++ { "tmpfs", "/run/lock", "tmpfs", "mode=1777,size=5242880", MS_NOSUID|MS_NOEXEC|MS_NODEV,
++ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate,memory_recursiveprot", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
+ { "cgroup2", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+diff --git a/tmpfiles.d/legacy.conf.in b/tmpfiles.d/legacy.conf.in
+index 4f2c0d7..fb1d6bf 100644
+--- a/tmpfiles.d/legacy.conf.in
++++ b/tmpfiles.d/legacy.conf.in
+@@ -10,7 +10,6 @@
+ # These files are considered legacy and are unnecessary on legacy-free
+ # systems.
+
+-d /run/lock 0755 root root -
+ L /var/lock - - - - ../run/lock
+ {% if CREATE_LOG_DIRS %}
+ L /var/log/README - - - - ../..{{DOC_DIR}}/README.logs
diff --git a/debian/patches/debian/Move-sysusers.d-sysctl.d-binfmt.d-modules-load.d-back-to-.patch b/debian/patches/debian/Move-sysusers.d-sysctl.d-binfmt.d-modules-load.d-back-to-.patch
new file mode 100644
index 0000000..9a39629
--- /dev/null
+++ b/debian/patches/debian/Move-sysusers.d-sysctl.d-binfmt.d-modules-load.d-back-to-.patch
@@ -0,0 +1,68 @@
+From: Michael Biebl <biebl@debian.org>
+Date: Thu, 15 Oct 2020 23:11:01 +0200
+Subject: Move sysusers.d/sysctl.d/binfmt.d/modules-load.d back to /usr
+
+In Debian, late mounting of /usr is no longer supported, so it is safe
+to install those files in /usr.
+We want those facilities in /usr, not /, as this will make an eventual
+switch to a merged-usr setup easier.
+
+Closes: #971282
+---
+ src/core/systemd.pc.in | 8 ++++----
+ src/libsystemd/sd-path/sd-path.c | 8 ++++----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in
+index 693433b..8368a3f 100644
+--- a/src/core/systemd.pc.in
++++ b/src/core/systemd.pc.in
+@@ -67,16 +67,16 @@ tmpfilesdir=${tmpfiles_dir}
+
+ user_tmpfiles_dir=${prefix}/share/user-tmpfiles.d
+
+-sysusers_dir=${rootprefix}/lib/sysusers.d
++sysusers_dir=${prefix}/lib/sysusers.d
+ sysusersdir=${sysusers_dir}
+
+-sysctl_dir=${rootprefix}/lib/sysctl.d
++sysctl_dir=${prefix}/lib/sysctl.d
+ sysctldir=${sysctl_dir}
+
+-binfmt_dir=${rootprefix}/lib/binfmt.d
++binfmt_dir=${prefix}/lib/binfmt.d
+ binfmtdir=${binfmt_dir}
+
+-modules_load_dir=${rootprefix}/lib/modules-load.d
++modules_load_dir=${prefix}/lib/modules-load.d
+ modulesloaddir=${modules_load_dir}
+
+ catalog_dir=${prefix}/lib/systemd/catalog
+diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c
+index ac33e34..f0615ff 100644
+--- a/src/libsystemd/sd-path/sd-path.c
++++ b/src/libsystemd/sd-path/sd-path.c
+@@ -362,19 +362,19 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
+ return 0;
+
+ case SD_PATH_SYSUSERS:
+- *ret = ROOTPREFIX_NOSLASH "/lib/sysusers.d";
++ *ret = "/usr/lib/sysusers.d";
+ return 0;
+
+ case SD_PATH_SYSCTL:
+- *ret = ROOTPREFIX_NOSLASH "/lib/sysctl.d";
++ *ret = "/usr/lib/sysctl.d";
+ return 0;
+
+ case SD_PATH_BINFMT:
+- *ret = ROOTPREFIX_NOSLASH "/lib/binfmt.d";
++ *ret = "/usr/lib/binfmt.d";
+ return 0;
+
+ case SD_PATH_MODULES_LOAD:
+- *ret = ROOTPREFIX_NOSLASH "/lib/modules-load.d";
++ *ret = "/usr/lib/modules-load.d";
+ return 0;
+
+ case SD_PATH_CATALOG:
diff --git a/debian/patches/debian/Only-start-logind-if-dbus-is-installed.patch b/debian/patches/debian/Only-start-logind-if-dbus-is-installed.patch
new file mode 100644
index 0000000..825c767
--- /dev/null
+++ b/debian/patches/debian/Only-start-logind-if-dbus-is-installed.patch
@@ -0,0 +1,28 @@
+From: Martin Pitt <martin.pitt@ubuntu.com>
+Date: Mon, 9 Feb 2015 10:53:43 +0100
+Subject: Only start logind if dbus is installed
+
+logind fails to start in environments without dbus, such as LXC containers or
+servers. Add a startup condition to avoid the very noisy startup failure.
+
+Consider both dbus-daemon (the reference implementation) and
+dbus-broker.
+
+Part of #772700
+---
+ units/systemd-logind.service.in | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in
+index 042ea75..89a7c89 100644
+--- a/units/systemd-logind.service.in
++++ b/units/systemd-logind.service.in
+@@ -16,6 +16,8 @@ Documentation=man:org.freedesktop.login1(5)
+
+ Wants=user.slice modprobe@drm.service
+ After=nss-user-lookup.target user.slice modprobe@drm.service
++ConditionPathExists=|/lib/systemd/system/dbus.service
++ConditionPathExists=|/lib/systemd/system/dbus-broker.service
+
+ # Ask for the dbus socket.
+ Wants=dbus.socket
diff --git a/debian/patches/debian/Re-enable-journal-forwarding-to-syslog.patch b/debian/patches/debian/Re-enable-journal-forwarding-to-syslog.patch
new file mode 100644
index 0000000..838c4e4
--- /dev/null
+++ b/debian/patches/debian/Re-enable-journal-forwarding-to-syslog.patch
@@ -0,0 +1,56 @@
+From: Martin Pitt <martin.pitt@ubuntu.com>
+Date: Fri, 28 Nov 2014 14:43:25 +0100
+Subject: Re-enable journal forwarding to syslog
+
+Revert upstream commit 46b131574fdd7d77 for now, until Debian's sysloggers
+can/do all read from the journal directly. See
+
+ http://lists.freedesktop.org/archives/systemd-devel/2014-November/025550.html
+
+for details. Once we grow a journal.conf.d/ directory, sysloggers can be moved
+to pulling from the journal one by one and disable forwarding again in such a
+conf.d snippet.
+---
+ man/journald.conf.xml | 2 +-
+ src/journal/journald-server.c | 1 +
+ src/journal/journald.conf | 2 +-
+ 3 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/man/journald.conf.xml b/man/journald.conf.xml
+index 2db6a0f..160544a 100644
+--- a/man/journald.conf.xml
++++ b/man/journald.conf.xml
+@@ -356,7 +356,7 @@
+ traditional syslog daemon, to the kernel log buffer (kmsg), to the system console, or sent as wall
+ messages to all logged-in users. These options take boolean arguments. If forwarding to syslog is
+ enabled but nothing reads messages from the socket, forwarding to syslog has no effect. By default,
+- only forwarding to wall is enabled. These settings may be overridden at boot time with the kernel
++ only forwarding to syslog and wall is enabled. These settings may be overridden at boot time with the kernel
+ command line options <literal>systemd.journald.forward_to_syslog</literal>,
+ <literal>systemd.journald.forward_to_kmsg</literal>,
+ <literal>systemd.journald.forward_to_console</literal>, and
+diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
+index 77aef79..a78e2c0 100644
+--- a/src/journal/journald-server.c
++++ b/src/journal/journald-server.c
+@@ -2289,6 +2289,7 @@ int server_init(Server *s, const char *namespace) {
+ .ratelimit_interval = DEFAULT_RATE_LIMIT_INTERVAL,
+ .ratelimit_burst = DEFAULT_RATE_LIMIT_BURST,
+
++ .forward_to_syslog = true,
+ .forward_to_wall = true,
+
+ .max_file_usec = DEFAULT_MAX_FILE_USEC,
+diff --git a/src/journal/journald.conf b/src/journal/journald.conf
+index 5a60a9d..64f4d4b 100644
+--- a/src/journal/journald.conf
++++ b/src/journal/journald.conf
+@@ -32,7 +32,7 @@
+ #RuntimeMaxFiles=100
+ #MaxRetentionSec=
+ #MaxFileSec=1month
+-#ForwardToSyslog=no
++#ForwardToSyslog=yes
+ #ForwardToKMsg=no
+ #ForwardToConsole=no
+ #ForwardToWall=yes
diff --git a/debian/patches/debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch b/debian/patches/debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch
new file mode 100644
index 0000000..31d6099
--- /dev/null
+++ b/debian/patches/debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch
@@ -0,0 +1,37 @@
+From: Martin Pitt <martin.pitt@ubuntu.com>
+Date: Mon, 27 Apr 2015 15:29:13 +0200
+Subject: Revert "core: one step back again,
+ for nspawn we actually can't wait for cgroups running empty since systemd
+ will get exactly zero notifications about it"
+
+This reverts commit 743970d2ea6d08aa7c7bff8220f6b7702f2b1db7.
+
+Bug-Debian: https://bugs.debian.org/784720
+Bug-Ubuntu: https://launchpad.net/bugs/1448259
+Bug-Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=1141137
+---
+ src/core/unit.c | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+diff --git a/src/core/unit.c b/src/core/unit.c
+index 52df7ce..fb9a740 100644
+--- a/src/core/unit.c
++++ b/src/core/unit.c
+@@ -4646,16 +4646,7 @@ int unit_kill_context(
+
+ } else if (r > 0) {
+
+- /* FIXME: For now, on the legacy hierarchy, we will not wait for the cgroup members to die if
+- * we are running in a container or if this is a delegation unit, simply because cgroup
+- * notification is unreliable in these cases. It doesn't work at all in containers, and outside
+- * of containers it can be confused easily by left-over directories in the cgroup — which
+- * however should not exist in non-delegated units. On the unified hierarchy that's different,
+- * there we get proper events. Hence rely on them. */
+-
+- if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0 ||
+- (detect_container() == 0 && !unit_cgroup_delegate(u)))
+- wait_for_exit = true;
++ wait_for_exit = true;
+
+ if (send_sighup) {
+ set_free(pid_set);
diff --git a/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch b/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch
new file mode 100644
index 0000000..e570fff
--- /dev/null
+++ b/debian/patches/debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch
@@ -0,0 +1,71 @@
+From: Martin Pitt <martin.pitt@ubuntu.com>
+Date: Sat, 27 Feb 2016 12:27:06 +0100
+Subject: Revert "core: set RLIMIT_CORE to unlimited by default"
+
+Partially revert commit 15a900327ab as this completely breaks core dumps
+without systemd-coredump. It's also contradicting core(8), and it's not
+systemd's place to redefine the kernel definitions of core files.
+
+Commit bdfd7b2c now honours the process' RLIMIT_CORE for systemd-coredump. This
+isn't what RLIMIT_CORE is supposed to do (it limits the size of the core
+*file*, but the kernel deliberately ignores it for piping), so set a static
+2^63 core size limit for systemd-coredump to go back to the previous behaviour
+(otherwise the change above would break systemd-coredump).
+
+Bug-Debian: https://bugs.debian.org/815020
+---
+ src/core/main.c | 20 --------------------
+ sysctl.d/50-coredump.conf.in | 2 +-
+ 2 files changed, 1 insertion(+), 21 deletions(-)
+
+diff --git a/src/core/main.c b/src/core/main.c
+index 1c4b464..e84e7dd 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -1650,24 +1650,6 @@ static void cmdline_take_random_seed(void) {
+ "This functionality should not be used outside of testing environments.");
+ }
+
+-static void initialize_coredump(bool skip_setup) {
+-#if ENABLE_COREDUMP
+- if (getpid_cached() != 1)
+- return;
+-
+- /* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour
+- * the limit) will process core dumps for system services by default. */
+- if (setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0)
+- log_warning_errno(errno, "Failed to set RLIMIT_CORE: %m");
+-
+- /* But at the same time, turn off the core_pattern logic by default, so that no coredumps are stored
+- * until the systemd-coredump tool is enabled via sysctl. However it can be changed via the kernel
+- * command line later so core dumps can still be generated during early startup and in initrd. */
+- if (!skip_setup)
+- disable_coredumps();
+-#endif
+-}
+-
+ static void initialize_core_pattern(bool skip_setup) {
+ int r;
+
+@@ -2814,8 +2796,6 @@ int main(int argc, char *argv[]) {
+ kernel_timestamp = DUAL_TIMESTAMP_NULL;
+ }
+
+- initialize_coredump(skip_setup);
+-
+ r = fixup_environment();
+ if (r < 0) {
+ log_emergency_errno(r, "Failed to fix up PID 1 environment: %m");
+diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in
+index 5fb551a..13495f1 100644
+--- a/sysctl.d/50-coredump.conf.in
++++ b/sysctl.d/50-coredump.conf.in
+@@ -13,7 +13,7 @@
+ # the core dump.
+ #
+ # See systemd-coredump(8) and core(5).
+-kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h
++kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t 9223372036854775808 %h
+
+ # Allow 16 coredumps to be dispatched in parallel by the kernel.
+ # We collect metadata from /proc/%P/, and thus need to make sure the crashed
diff --git a/debian/patches/debian/Skip-filesystem-check-if-already-done-by-the-initram.patch b/debian/patches/debian/Skip-filesystem-check-if-already-done-by-the-initram.patch
new file mode 100644
index 0000000..c819275
--- /dev/null
+++ b/debian/patches/debian/Skip-filesystem-check-if-already-done-by-the-initram.patch
@@ -0,0 +1,57 @@
+From: Nis Martensen <nis.martensen@web.de>
+Date: Tue, 19 Jan 2016 22:01:43 +0100
+Subject: Skip filesystem check if already done by the initramfs
+
+Newer versions of initramfs-tools already fsck and mount / and /usr in
+the initramfs. Skip the filesystem check in this case.
+
+Based on a previous patch by Michael Biebl <biebl@debian.org>.
+
+Closes: #782522
+Closes: #810748
+---
+ src/fstab-generator/fstab-generator.c | 11 ++++++++---
+ units/systemd-fsck-root.service.in | 1 +
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
+index 63f0f36..8b3c732 100644
+--- a/src/fstab-generator/fstab-generator.c
++++ b/src/fstab-generator/fstab-generator.c
+@@ -368,6 +368,7 @@ static int add_mount(
+ _cleanup_strv_free_ char **wanted_by = NULL, **required_by = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ int r;
++ struct stat sb;
+
+ assert(what);
+ assert(where);
+@@ -455,9 +456,13 @@ static int add_mount(
+ fprintf(f, "Before=%s\n", target_unit);
+
+ if (passno != 0) {
+- r = generator_write_fsck_deps(f, dest, what, where, fstype);
+- if (r < 0)
+- return r;
++ if (streq(where, "/usr") && stat("/run/initramfs/fsck-usr", &sb) == 0)
++ ; /* skip /usr fsck if it has already been checked in the initramfs */
++ else {
++ r = generator_write_fsck_deps(f, dest, what, where, fstype);
++ if (r < 0)
++ return r;
++ }
+ }
+
+ r = generator_write_blockdev_dependency(f, what);
+diff --git a/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in
+index 4b1cd43..07590fd 100644
+--- a/units/systemd-fsck-root.service.in
++++ b/units/systemd-fsck-root.service.in
+@@ -16,6 +16,7 @@ Before=local-fs.target shutdown.target
+ Wants=systemd-fsckd.socket
+ After=systemd-fsckd.socket
+ ConditionPathIsReadWrite=!/
++ConditionPathExists=!/run/initramfs/fsck-root
+ OnFailure=emergency.target
+ OnFailureJobMode=replace-irreversibly
+
diff --git a/debian/patches/debian/Skip-flaky-test_resolved_domain_restricted_dns-in-network.patch b/debian/patches/debian/Skip-flaky-test_resolved_domain_restricted_dns-in-network.patch
new file mode 100644
index 0000000..82ee455
--- /dev/null
+++ b/debian/patches/debian/Skip-flaky-test_resolved_domain_restricted_dns-in-network.patch
@@ -0,0 +1,24 @@
+From: Michael Biebl <biebl@debian.org>
+Date: Tue, 13 Dec 2022 00:32:17 +0100
+Subject: Skip flaky test_resolved_domain_restricted_dns in networkd-test.py
+
+This test is part of DnsmasqClientTest and does not work reliably under
+LXC/debci, so skip it for the time being.
+
+Closes: #1025908
+---
+ test/networkd-test.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/test/networkd-test.py b/test/networkd-test.py
+index 84013e7..172b3b3 100755
+--- a/test/networkd-test.py
++++ b/test/networkd-test.py
+@@ -633,6 +633,7 @@ class DnsmasqClientTest(ClientTestBase, unittest.TestCase):
+ with open(path) as f:
+ sys.stdout.write('\n\n---- {} ----\n{}\n------\n\n'.format(os.path.basename(path), f.read()))
+
++ @unittest.skip("test is flaky: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1025908")
+ def test_resolved_domain_restricted_dns(self):
+ '''resolved: domain-restricted DNS servers'''
+
diff --git a/debian/patches/debian/Use-Debian-specific-config-files.patch b/debian/patches/debian/Use-Debian-specific-config-files.patch
new file mode 100644
index 0000000..ce1a2b8
--- /dev/null
+++ b/debian/patches/debian/Use-Debian-specific-config-files.patch
@@ -0,0 +1,363 @@
+From: Michael Biebl <biebl@debian.org>
+Date: Thu, 18 Jul 2013 20:11:02 +0200
+Subject: Use Debian specific config files
+
+Use /etc/default/locale instead of /etc/locale.conf for locale settings.
+
+Use /etc/default/keyboard instead of /etc/X11/xorg.conf.d/00-keyboard.conf for
+keyboard configuration.
+---
+ src/firstboot/firstboot.c | 12 ++-
+ src/locale/localed-util.c | 189 ++++++++++++++++++++--------------------------
+ src/shared/locale-setup.c | 24 ++++--
+ 3 files changed, 108 insertions(+), 117 deletions(-)
+
+diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
+index dee2742..d66cf87 100644
+--- a/src/firstboot/firstboot.c
++++ b/src/firstboot/firstboot.c
+@@ -311,12 +311,16 @@ static int prompt_locale(void) {
+ }
+
+ static int process_locale(void) {
+- const char *etc_localeconf;
++ const char *etc_localeconf, *path = "/etc/locale.conf";
+ char* locales[3];
+ unsigned i = 0;
+- int r;
++ int r = 0;
++
++ if (laccess(path, F_OK) < 0 && errno == ENOENT)
++ path = "/etc/default/locale";
++
++ etc_localeconf = prefix_roota(arg_root, path);
+
+- etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf");
+ if (laccess(etc_localeconf, F_OK) >= 0 && !arg_force) {
+ log_debug("Found %s, assuming locale information has been configured.",
+ etc_localeconf);
+@@ -326,7 +330,7 @@ static int process_locale(void) {
+ if (arg_copy_locale && arg_root) {
+
+ (void) mkdir_parents(etc_localeconf, 0755);
+- r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0, 0, COPY_REFLINK);
++ r = copy_file(path, etc_localeconf, 0, 0644, 0, 0, COPY_REFLINK);
+ if (r != -ENOENT) {
+ if (r < 0)
+ return log_error_errno(r, "Failed to copy %s: %m", etc_localeconf);
+diff --git a/src/locale/localed-util.c b/src/locale/localed-util.c
+index 4d021fb..d9050c0 100644
+--- a/src/locale/localed-util.c
++++ b/src/locale/localed-util.c
+@@ -128,7 +128,6 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
+
+ int x11_read_data(Context *c, sd_bus_message *m) {
+ _cleanup_fclose_ FILE *f = NULL;
+- bool in_section = false;
+ struct stat st;
+ usec_t t;
+ int r;
+@@ -142,7 +141,7 @@ int x11_read_data(Context *c, sd_bus_message *m) {
+ c->x11_cache = sd_bus_message_ref(m);
+ }
+
+- if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) < 0) {
++ if (stat("/etc/default/keyboard", &st) < 0) {
+ if (errno != ENOENT)
+ return -errno;
+
+@@ -159,60 +158,14 @@ int x11_read_data(Context *c, sd_bus_message *m) {
+ c->x11_mtime = t;
+ context_free_x11(c);
+
+- f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
+- if (!f)
+- return -errno;
+-
+- for (;;) {
+- _cleanup_free_ char *line = NULL;
+- char *l;
+-
+- r = read_line(f, LONG_LINE_MAX, &line);
+- if (r < 0)
+- return r;
+- if (r == 0)
+- break;
+-
+- l = strstrip(line);
+- if (IN_SET(l[0], 0, '#'))
+- continue;
+-
+- if (in_section && first_word(l, "Option")) {
+- _cleanup_strv_free_ char **a = NULL;
+-
+- r = strv_split_full(&a, l, WHITESPACE, EXTRACT_UNQUOTE);
+- if (r < 0)
+- return r;
+-
+- if (strv_length(a) == 3) {
+- char **p = NULL;
+-
+- if (streq(a[1], "XkbLayout"))
+- p = &c->x11_layout;
+- else if (streq(a[1], "XkbModel"))
+- p = &c->x11_model;
+- else if (streq(a[1], "XkbVariant"))
+- p = &c->x11_variant;
+- else if (streq(a[1], "XkbOptions"))
+- p = &c->x11_options;
+-
+- if (p)
+- free_and_replace(*p, a[2]);
+- }
+-
+- } else if (!in_section && first_word(l, "Section")) {
+- _cleanup_strv_free_ char **a = NULL;
+-
+- r = strv_split_full(&a, l, WHITESPACE, EXTRACT_UNQUOTE);
+- if (r < 0)
+- return -ENOMEM;
+-
+- if (strv_length(a) == 2 && streq(a[1], "InputClass"))
+- in_section = true;
+-
+- } else if (in_section && first_word(l, "EndSection"))
+- in_section = false;
+- }
++ r = parse_env_file(NULL, "/etc/default/keyboard",
++ "XKBMODEL", &c->x11_model,
++ "XKBLAYOUT", &c->x11_layout,
++ "XKBVARIANT", &c->x11_variant,
++ "XKBOPTIONS", &c->x11_options);
++
++ if (r < 0)
++ return r;
+
+ return 0;
+ }
+@@ -253,69 +206,93 @@ int vconsole_write_data(Context *c) {
+ }
+
+ int x11_write_data(Context *c) {
+- _cleanup_fclose_ FILE *f = NULL;
+- _cleanup_free_ char *temp_path = NULL;
+ struct stat st;
+ int r;
++ char *t, **l = NULL;
+
+- if (isempty(c->x11_layout) &&
+- isempty(c->x11_model) &&
+- isempty(c->x11_variant) &&
+- isempty(c->x11_options)) {
++ r = load_env_file(NULL, "/etc/default/keyboard", &l);
++ if (r < 0 && r != -ENOENT)
++ return r;
+
+- if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
++ /* This could perhaps be done more elegantly using an array
++ * like we do for the locale, instead of struct
++ */
++ if (isempty(c->x11_layout)) {
++ l = strv_env_unset(l, "XKBLAYOUT");
++ } else {
++ if (asprintf(&t, "XKBLAYOUT=%s", c->x11_layout) < 0) {
++ strv_free(l);
++ return -ENOMEM;
++ }
++
++ r = strv_env_replace_consume(&l, t);
++ if (r < 0) {
++ strv_free(l);
++ return r;
++ }
++ }
++
++ if (isempty(c->x11_model)) {
++ l = strv_env_unset(l, "XKBMODEL");
++ } else {
++ if (asprintf(&t, "XKBMODEL=%s", c->x11_model) < 0) {
++ strv_free(l);
++ return -ENOMEM;
++ }
++
++ r = strv_env_replace_consume(&l, t);
++ if (r < 0) {
++ strv_free(l);
++ return r;
++ }
++ }
++
++ if (isempty(c->x11_variant)) {
++ l = strv_env_unset(l, "XKBVARIANT");
++ } else {
++ if (asprintf(&t, "XKBVARIANT=%s", c->x11_variant) < 0) {
++ strv_free(l);
++ return -ENOMEM;
++ }
++
++ r = strv_env_replace_consume(&l, t);
++ if (r < 0) {
++ strv_free(l);
++ return r;
++ }
++ }
++
++ if (isempty(c->x11_options)) {
++ l = strv_env_unset(l, "XKBOPTIONS");
++ } else {
++ if (asprintf(&t, "XKBOPTIONS=%s", c->x11_options) < 0) {
++ strv_free(l);
++ return -ENOMEM;
++ }
++
++ r = strv_env_replace_consume(&l, t);
++ if (r < 0) {
++ strv_free(l);
++ return r;
++ }
++ }
++
++ if (strv_isempty(l)) {
++ strv_free(l);
++
++ if (unlink("/etc/default/keyboard") < 0)
+ return errno == ENOENT ? 0 : -errno;
+
+ c->vc_mtime = USEC_INFINITY;
+ return 0;
+ }
+
+- (void) mkdir_p_label("/etc/X11/xorg.conf.d", 0755);
+- r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path);
+- if (r < 0)
+- return r;
++ r = write_env_file("/etc/default/keyboard", l);
++ strv_free(l);
+
+- (void) fchmod(fileno(f), 0644);
+-
+- fputs("# Written by systemd-localed(8), read by systemd-localed and Xorg. It's\n"
+- "# probably wise not to edit this file manually. Use localectl(1) to\n"
+- "# instruct systemd-localed to update it.\n"
+- "Section \"InputClass\"\n"
+- " Identifier \"system-keyboard\"\n"
+- " MatchIsKeyboard \"on\"\n", f);
+-
+- if (!isempty(c->x11_layout))
+- fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout);
+-
+- if (!isempty(c->x11_model))
+- fprintf(f, " Option \"XkbModel\" \"%s\"\n", c->x11_model);
+-
+- if (!isempty(c->x11_variant))
+- fprintf(f, " Option \"XkbVariant\" \"%s\"\n", c->x11_variant);
+-
+- if (!isempty(c->x11_options))
+- fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options);
+-
+- fputs("EndSection\n", f);
+-
+- r = fflush_sync_and_check(f);
+- if (r < 0)
+- goto fail;
+-
+- if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) {
+- r = -errno;
+- goto fail;
+- }
+-
+- if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) >= 0)
++ if (r >= 0 && stat("/etc/default/keyboard", &st) >= 0)
+ c->x11_mtime = timespec_load(&st.st_mtim);
+
+- return 0;
+-
+-fail:
+- if (temp_path)
+- (void) unlink(temp_path);
+-
+ return r;
+ }
+
+diff --git a/src/shared/locale-setup.c b/src/shared/locale-setup.c
+index b8c6647..be7efcb 100644
+--- a/src/shared/locale-setup.c
++++ b/src/shared/locale-setup.c
+@@ -49,14 +49,20 @@ int locale_context_load(LocaleContext *c, LocaleLoadFlag flag) {
+ }
+
+ if (FLAGS_SET(flag, LOCALE_LOAD_LOCALE_CONF)) {
++ const char *path = "/etc/locale.conf";
+ struct stat st;
+ usec_t t;
+
+- r = stat("/etc/locale.conf", &st);
++ r = stat(path, &st);
++ if (r < 0 && errno == ENOENT) {
++ path = "/etc/default/locale";
++ r = stat(path, &st);
++ }
+ if (r < 0 && errno != ENOENT)
+- return log_debug_errno(errno, "Failed to stat /etc/locale.conf: %m");
++ return log_debug_errno(errno, "Failed to stat %s: %m", path);
+
+ if (r >= 0) {
++
+ /* If mtime is not changed, then we do not need to re-read the file. */
+ t = timespec_load(&st.st_mtim);
+ if (c->mtime != USEC_INFINITY && t == c->mtime)
+@@ -65,7 +71,7 @@ int locale_context_load(LocaleContext *c, LocaleLoadFlag flag) {
+ locale_context_clear(c);
+ c->mtime = t;
+
+- r = parse_env_file(NULL, "/etc/locale.conf",
++ r = parse_env_file(NULL, path,
+ "LANG", &c->locale[VARIABLE_LANG],
+ "LANGUAGE", &c->locale[VARIABLE_LANGUAGE],
+ "LC_CTYPE", &c->locale[VARIABLE_LC_CTYPE],
+@@ -81,7 +87,7 @@ int locale_context_load(LocaleContext *c, LocaleLoadFlag flag) {
+ "LC_MEASUREMENT", &c->locale[VARIABLE_LC_MEASUREMENT],
+ "LC_IDENTIFICATION", &c->locale[VARIABLE_LC_IDENTIFICATION]);
+ if (r < 0)
+- return log_debug_errno(r, "Failed to read /etc/locale.conf: %m");
++ return log_debug_errno(r, "Failed to read %s: %m", path);
+
+ goto finalize;
+ }
+@@ -149,17 +155,21 @@ int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset) {
+ _cleanup_strv_free_ char **set = NULL, **unset = NULL;
+ struct stat st;
+ int r;
++ const char *path = "/etc/locale.conf";
+
+ assert(c);
+
+ /* Set values will be returned as strv in *ret on success. */
+
++ if (access(path, F_OK) < 0 && errno == ENOENT)
++ path = "/etc/default/locale";
++
+ r = locale_context_build_env(c, &set, ret_unset ? &unset : NULL);
+ if (r < 0)
+ return r;
+
+ if (strv_isempty(set)) {
+- if (unlink("/etc/locale.conf") < 0)
++ if (unlink(path) < 0)
+ return errno == ENOENT ? 0 : -errno;
+
+ c->mtime = USEC_INFINITY;
+@@ -170,11 +180,11 @@ int locale_context_save(LocaleContext *c, char ***ret_set, char ***ret_unset) {
+ return 0;
+ }
+
+- r = write_env_file_label("/etc/locale.conf", set);
++ r = write_env_file_label(path, set);
+ if (r < 0)
+ return r;
+
+- if (stat("/etc/locale.conf", &st) >= 0)
++ if (stat(path, &st) >= 0)
+ c->mtime = timespec_load(&st.st_mtim);
+
+ if (ret_set)
diff --git a/debian/patches/debian/deny-list-upstream-test-02-ppc64el.patch b/debian/patches/debian/deny-list-upstream-test-02-ppc64el.patch
new file mode 100644
index 0000000..ee49d27
--- /dev/null
+++ b/debian/patches/debian/deny-list-upstream-test-02-ppc64el.patch
@@ -0,0 +1,17 @@
+From: Dan Streetman <ddstreet@canonical.com>
+Date: Wed, 6 Nov 2019 09:14:54 -0500
+Subject: deny-list-upstream-test-02-ppc64el
+
+Bug: https://github.com/systemd/systemd/issues/11612
+---
+ test/TEST-02-UNITTESTS/deny-list-upstream-ci-ppc64el | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 test/TEST-02-UNITTESTS/deny-list-upstream-ci-ppc64el
+
+diff --git a/test/TEST-02-UNITTESTS/deny-list-upstream-ci-ppc64el b/test/TEST-02-UNITTESTS/deny-list-upstream-ci-ppc64el
+new file mode 100644
+index 0000000..52877fc
+--- /dev/null
++++ b/test/TEST-02-UNITTESTS/deny-list-upstream-ci-ppc64el
+@@ -0,0 +1 @@
++# unknown reason for failing, tracked in https://github.com/systemd/systemd/issues/11612
diff --git a/debian/patches/debian/deny-list-upstream-test-25.patch b/debian/patches/debian/deny-list-upstream-test-25.patch
new file mode 100644
index 0000000..ec6c211
--- /dev/null
+++ b/debian/patches/debian/deny-list-upstream-test-25.patch
@@ -0,0 +1,17 @@
+From: Dan Streetman <ddstreet@canonical.com>
+Date: Wed, 6 Nov 2019 09:14:50 -0500
+Subject: deny-list-upstream-test-25
+
+Bug: https://github.com/systemd/systemd/issues/13973
+---
+ test/TEST-25-IMPORT/deny-list-upstream-ci | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 test/TEST-25-IMPORT/deny-list-upstream-ci
+
+diff --git a/test/TEST-25-IMPORT/deny-list-upstream-ci b/test/TEST-25-IMPORT/deny-list-upstream-ci
+new file mode 100644
+index 0000000..47a5f15
+--- /dev/null
++++ b/test/TEST-25-IMPORT/deny-list-upstream-ci
+@@ -0,0 +1 @@
++# unknown failure; tracked in https://github.com/systemd/systemd/issues/13973
diff --git a/debian/patches/debian/fsckd-daemon-for-inter-fsckd-communication.patch b/debian/patches/debian/fsckd-daemon-for-inter-fsckd-communication.patch
new file mode 100644
index 0000000..103b44a
--- /dev/null
+++ b/debian/patches/debian/fsckd-daemon-for-inter-fsckd-communication.patch
@@ -0,0 +1,1068 @@
+From: Didier Roche <didrocks@ubuntu.com>
+Date: Fri, 22 May 2015 13:04:38 +0200
+Subject: fsckd daemon for inter-fsckd communication
+
+Global logic:
+Add systemd-fsckd multiplexer which accepts multiple (via systemd-fsck's
+/run/systemd/fsck.progress socket) fsck instances to connect to it and sends
+progress report. systemd-fsckd then computes and writes to /dev/console the
+number of devices currently being checked and the minimum fsck progress.
+
+Plymouth and user interaction:
+Forward the progress to plymouth and support canellation of in progress fsck.
+Try to connect and send to plymouth (if running) some checked report progress,
+using direct plymouth protocole.
+
+Update message is the following:
+fsckd:<num_devices>:<progress>:<string>
+* num_devices corresponds to the current number of devices being checked (int)
+* progress corresponds to the current minimum percentage of all devices being
+ checked (float, from 0 to 100)
+* string is a translated message ready to be displayed by the plymouth theme
+ displaying the information above. It can be overridden by plymouth themes
+ supporting i18n.
+
+Grab in fsckd plymouth watch key Control+C, and propagate this cancel request
+to systemd-fsck which will terminate fsck.
+
+Send a message to signal to user what key we are grabbing for fsck cancel.
+
+Message is: fsckd-cancel-msg:<string>
+Where string is a translated string ready to be displayed by the plymouth theme
+indicating that Control+C can be used to cancel current checks. It can be
+overridden (matching only fsckd-cancel-msg prefix) for themes supporting i18n.
+
+Misc:
+systemd-fsckd stops on idle when no fsck is connected.
+Add man page explaining the plymouth theme protocol, usage of the daemon
+as well as the socket activation part. Adapt existing fsck man page.
+
+Note that fsckd had lived in the upstream tree for a while, but was removed.
+More information at
+http://lists.freedesktop.org/archives/systemd-devel/2015-April/030175.html
+-
+---
+ man/rules/meson.build | 1 +
+ man/systemd-fsckd.service.xml | 162 +++++++++
+ meson.build | 9 +
+ po/POTFILES.in | 1 +
+ src/fsckd/fsckd.c | 702 +++++++++++++++++++++++++++++++++++++
+ units/meson.build | 2 +
+ units/systemd-fsck-root.service.in | 2 +
+ units/systemd-fsck@.service.in | 3 +-
+ units/systemd-fsckd.service.in | 17 +
+ units/systemd-fsckd.socket | 15 +
+ 10 files changed, 913 insertions(+), 1 deletion(-)
+ create mode 100644 man/systemd-fsckd.service.xml
+ create mode 100644 src/fsckd/fsckd.c
+ create mode 100644 units/systemd-fsckd.service.in
+ create mode 100644 units/systemd-fsckd.socket
+
+diff --git a/man/rules/meson.build b/man/rules/meson.build
+index 4819b15..4b52db1 100644
+--- a/man/rules/meson.build
++++ b/man/rules/meson.build
+@@ -892,6 +892,7 @@ manpages = [
+ '8',
+ ['systemd-fsck', 'systemd-fsck-root.service', 'systemd-fsck-usr.service'],
+ ''],
++ ['systemd-fsckd.service', '8', ['systemd-fsckd.socket', 'systemd-fsckd'], ''],
+ ['systemd-fstab-generator', '8', [], ''],
+ ['systemd-getty-generator', '8', [], ''],
+ ['systemd-gpt-auto-generator', '8', [], 'HAVE_BLKID'],
+diff --git a/man/systemd-fsckd.service.xml b/man/systemd-fsckd.service.xml
+new file mode 100644
+index 0000000..b7ad58d
+--- /dev/null
++++ b/man/systemd-fsckd.service.xml
+@@ -0,0 +1,162 @@
++<?xml version="1.0"?>
++<!--*-nxml-*-->
++<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
++<!--
++ This file is part of systemd.
++
++ Copyright 2015 Canonical
++
++ systemd is free software; you can redistribute it and/or modify it
++ under the terms of the GNU Lesser General Public License as published by
++ the Free Software Foundation; either version 2.1 of the License, or
++ (at your option) any later version.
++
++ systemd is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public License
++ along with systemd; If not, see <http://www.gnu.org/licenses/>.
++-->
++<refentry id="systemd-fsckd.service" xmlns:xi="http://www.w3.org/2001/XInclude">
++
++ <refentryinfo>
++ <title>systemd-fsckd.service</title>
++ <productname>systemd</productname>
++
++ <authorgroup>
++ <author>
++ <contrib>Developer</contrib>
++ <firstname>Didier</firstname>
++ <surname>Roche</surname>
++ <email>didrocks@ubuntu.com</email>
++ </author>
++ </authorgroup>
++ </refentryinfo>
++
++ <refmeta>
++ <refentrytitle>systemd-fsckd.service</refentrytitle>
++ <manvolnum>8</manvolnum>
++ </refmeta>
++
++ <refnamediv>
++ <refname>systemd-fsckd.service</refname>
++ <refname>systemd-fsckd.socket</refname>
++ <refname>systemd-fsckd</refname>
++ <refpurpose>File system check progress reporting</refpurpose>
++ </refnamediv>
++
++ <refsynopsisdiv>
++ <para><filename>systemd-fsckd.service</filename></para>
++ <para><filename>systemd-fsckd.socket</filename></para>
++ <para><filename>/usr/lib/systemd/systemd-fsckd</filename></para>
++ </refsynopsisdiv>
++
++ <refsect1>
++ <title>Description</title>
++
++ <para><filename>systemd-fsckd.service</filename> is a service responsible
++ for receiving file system check progress, and communicating some
++ consolidated data to console and plymouth (if running). It also handles
++ possible check cancellations.</para>
++
++ <para><command>systemd-fsckd</command> receives messages about file
++ system check progress from <command>fsck</command> through an
++ UNIX domain socket. It can display the progress of the least advanced
++ fsck as well as the total number of devices being checked in parallel
++ to the console. It will also send progress messages to plymouth.
++ Both the raw data and translated messages are sent, so compiled
++ plymouth themes can use the raw data to display custom messages, and
++ scripted themes, not supporting i18n, can display the translated
++ versions.</para>
++
++ <para><command>systemd-fsckd</command> will instruct plymouth to grab
++ Control+C keypresses. When the key is pressed, running checks will be
++ terminated. It will also cancel any newly connected fsck instances for
++ the lifetime of <filename>systemd-fsckd</filename>.</para>
++ </refsect1>
++
++ <refsect1>
++ <title>Protocol for communication with plymouth</title>
++
++ <para><filename>systemd-fsckd</filename> passes the
++ following messages to the theme:</para>
++
++ <para>Progress update, sent as a plymouth update message:
++ <literal>fsckd:&lt;num_devices&gt;:&lt;progress&gt;:&lt;string&gt;</literal>
++ <variablelist>
++ <varlistentry>
++ <term><literal>&lt;num_devices&gt;</literal></term>
++ <listitem><para>the current number of devices
++ being checked (int)</para></listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><literal>&lt;progress&gt;</literal></term>
++ <listitem><para>the current minimum percentage of
++ all devices being checking (float, from 0 to 100)</para></listitem>
++ </varlistentry>
++ <varlistentry>
++ <term><literal>&lt;string&gt;</literal></term>
++ <listitem><para>a translated message ready to be displayed
++ by the plymouth theme displaying the data above. It can be overridden
++ by themes supporting i18n.</para></listitem>
++ </varlistentry>
++ </variablelist>
++ </para>
++
++ <para>Cancel message, sent as a traditional plymouth message:
++ <literal>fsckd-cancel-msg:&lt;string&gt;</literal>
++ <variablelist>
++ <varlistentry>
++ <term><literal>&lt;strings&gt;</literal></term>
++ <listitem><para>a translated string ready to be displayed
++ by the plymouth theme indicating that Control+C can be used to cancel
++ current checks. It can be overridden (matching only
++ <literal>fsckd-cancel-msg</literal> prefix)
++ by themes supporting i18n.</para></listitem>
++ </varlistentry>
++ </variablelist>
++ </para>
++ </refsect1>
++
++ <refsect1>
++ <title>Options</title>
++
++ <para>The following options are understood:</para>
++
++ <variablelist>
++ <xi:include href="standard-options.xml" xpointer="help" />
++ <xi:include href="standard-options.xml" xpointer="version" />
++ </variablelist>
++
++ </refsect1>
++
++ <refsect1>
++ <title>Exit status</title>
++
++ <para>On success, 0 is returned, a non-zero failure
++ code otherwise. Note that the daemon stays idle for
++ a while to accept new <filename>fsck</filename>
++ connections before exiting.</para>
++ </refsect1>
++
++ <refsect1>
++ <title>See Also</title>
++ <para>
++ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
++ <citerefentry><refentrytitle>systemd-fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry><refentrytitle>systemd-quotacheck.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck.btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck.cramfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck.ext4</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck.fat</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck.hfsplus</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck.minix</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck.ntfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
++ <citerefentry project='man-pages'><refentrytitle>fsck.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
++ </para>
++ </refsect1>
++
++</refentry>
+diff --git a/meson.build b/meson.build
+index 27d95e7..9ace3e6 100644
+--- a/meson.build
++++ b/meson.build
+@@ -3368,6 +3368,15 @@ executable(
+ install : true,
+ install_dir : rootlibexecdir)
+
++executable(
++ 'systemd-fsckd',
++ 'src/fsckd/fsckd.c',
++ include_directories : includes,
++ link_with : [libshared],
++ install_rpath : rootpkglibdir,
++ install : true,
++ install_dir : rootlibexecdir)
++
+ executable(
+ 'systemd-sleep',
+ 'src/sleep/sleep.c',
+diff --git a/po/POTFILES.in b/po/POTFILES.in
+index e045852..131e4bc 100644
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -12,3 +12,4 @@ src/portable/org.freedesktop.portable1.policy
+ src/resolve/org.freedesktop.resolve1.policy
+ src/timedate/org.freedesktop.timedate1.policy
+ src/core/dbus-unit.c
++src/fsckd/fsckd.c
+diff --git a/src/fsckd/fsckd.c b/src/fsckd/fsckd.c
+new file mode 100644
+index 0000000..71dc86d
+--- /dev/null
++++ b/src/fsckd/fsckd.c
+@@ -0,0 +1,702 @@
++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
++
++/***
++ This file is part of systemd.
++
++ Copyright 2015 Canonical
++
++ Author:
++ Didier Roche <didrocks@ubuntu.com>
++
++ systemd is free software; you can redistribute it and/or modify it
++ under the terms of the GNU Lesser General Public License as published by
++ the Free Software Foundation; either version 2.1 of the License, or
++ (at your option) any later version.
++
++ systemd is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public License
++ along with systemd; If not, see <http://www.gnu.org/licenses/>.
++***/
++
++#include <getopt.h>
++#include <errno.h>
++#include <libintl.h>
++#include <math.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <sys/socket.h>
++#include <sys/types.h>
++#include <sys/un.h>
++#include <unistd.h>
++
++#include "sd-daemon.h"
++#include "build.h"
++#include "def.h"
++#include "sd-event.h"
++#include "log.h"
++#include "list.h"
++#include "macro.h"
++#include "socket-netlink.h"
++#include "socket-util.h"
++#include "fd-util.h"
++#include "string-util.h"
++#include "io-util.h"
++#include "util.h"
++#include "alloc-util.h"
++#include "locale-util.h"
++
++#define FSCKD_SOCKET_PATH "/run/systemd/fsck.progress"
++#define IDLE_TIME_SECONDS 30
++#define PLYMOUTH_REQUEST_KEY "K\2\2\3"
++#define CLIENTS_MAX 128
++
++struct Manager;
++
++typedef struct Client {
++ struct Manager *manager;
++ char *device_name;
++ /* device id refers to "fd <fd>" until it gets a name as "device_name" */
++ char *device_id;
++
++ pid_t fsck_pid;
++ FILE *fsck_f;
++
++ size_t cur;
++ size_t max;
++ int pass;
++
++ double percent;
++
++ bool cancelled;
++ bool bad_input;
++
++ sd_event_source *event_source;
++
++ LIST_FIELDS(struct Client, clients);
++} Client;
++
++typedef struct Manager {
++ sd_event *event;
++
++ LIST_HEAD(Client, clients);
++ unsigned n_clients;
++
++ size_t clear;
++
++ int connection_fd;
++ sd_event_source *connection_event_source;
++
++ bool show_status_console;
++
++ double percent;
++ int numdevices;
++
++ int plymouth_fd;
++ sd_event_source *plymouth_event_source;
++ bool plymouth_cancel_sent;
++
++ bool cancel_requested;
++} Manager;
++
++static Client* client_free(Client *c);
++static Manager* manager_free(Manager *m);
++
++DEFINE_TRIVIAL_CLEANUP_FUNC(Client*, client_free);
++DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
++
++static void init_gettext(void) {
++ setlocale(LC_ALL, "");
++ textdomain(GETTEXT_PACKAGE);
++}
++
++static bool plymouth_running(void) {
++ return access("/run/plymouth/pid", F_OK) >= 0;
++}
++
++static int manager_write_console(Manager *m, const char *message) {
++ _cleanup_fclose_ FILE *console = NULL;
++ int l;
++ size_t j;
++
++ assert(m);
++
++ if (!m->show_status_console)
++ return 0;
++
++ /* Nothing to display, and nothing to clear: return now. */
++ if (message == NULL && m->clear == 0) {
++ return 0;
++ }
++
++ /* Reduce the SAK window by opening and closing console on every request */
++ console = fopen("/dev/console", "we");
++ if (!console)
++ return -errno;
++
++ if (message) {
++ fprintf(console, "\r%s\r%n", message, &l);
++ if (m->clear < (size_t)l)
++ m->clear = (size_t)l;
++ } else {
++ fputc('\r', console);
++ for (j = 0; j < m->clear; j++)
++ fputc(' ', console);
++ fputc('\r', console);
++ }
++ fflush(console);
++
++ return 0;
++}
++
++static double compute_percent(int pass, size_t cur, size_t max) {
++ /* Values stolen from e2fsck */
++
++ static const double pass_table[] = {
++ 0, 70, 90, 92, 95, 100
++ };
++
++ if (pass <= 0)
++ return 0.0;
++
++ if ((unsigned) pass >= ELEMENTSOF(pass_table) || max == 0)
++ return 100.0;
++
++ return pass_table[pass-1] +
++ (pass_table[pass] - pass_table[pass-1]) *
++ (double) cur / max;
++}
++
++static int client_request_cancel(Client *c) {
++ assert(c);
++
++ if (c->cancelled)
++ return 0;
++
++ log_info("Request to cancel fsck for %s from fsckd", c->device_id);
++ if (kill(c->fsck_pid, SIGTERM) < 0) {
++ /* ignore the error and consider that cancel was sent if fsck just exited */
++ if (errno != ESRCH)
++ return log_error_errno(errno, "Cannot send cancel to fsck for %s: %m", c->device_id);
++ }
++
++ c->cancelled = true;
++ return 1;
++}
++
++static Client* client_free(Client *c) {
++ assert(c);
++
++ if (c->manager) {
++ LIST_REMOVE(clients, c->manager->clients, c);
++ c->manager->n_clients--;
++ }
++
++ sd_event_source_unref(c->event_source);
++ fclose(c->fsck_f);
++ if (c->device_name)
++ free(c->device_name);
++ if (c->device_id)
++ free(c->device_id);
++ return mfree(c);
++}
++
++static void manager_disconnect_plymouth(Manager *m) {
++ assert(m);
++
++ m->plymouth_event_source = sd_event_source_unref(m->plymouth_event_source);
++ m->plymouth_fd = safe_close(m->plymouth_fd);
++ m->plymouth_cancel_sent = false;
++}
++
++static int manager_plymouth_feedback_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
++ Manager *m = userdata;
++ char buffer[6];
++ ssize_t l;
++
++ assert(m);
++
++ l = read(m->plymouth_fd, buffer, sizeof(buffer));
++ if (l < 0) {
++ log_warning_errno(errno, "Got error while reading from plymouth: %m");
++ manager_disconnect_plymouth(m);
++ return -errno;
++ }
++ if (l == 0) {
++ manager_disconnect_plymouth(m);
++ return 0;
++ }
++
++ if (l > 1 && buffer[0] == '\15')
++ log_error("Message update to plymouth wasn't delivered successfully");
++
++ /* the only answer support type we requested is a key interruption */
++ if (l > 2 && buffer[0] == '\2' && buffer[5] == '\3') {
++ m->cancel_requested = true;
++
++ /* cancel all connected clients */
++ LIST_FOREACH(clients, current, m->clients)
++ client_request_cancel(current);
++ }
++
++ return 0;
++}
++
++static int manager_connect_plymouth(Manager *m) {
++ union sockaddr_union sa = PLYMOUTH_SOCKET;
++ int r;
++
++ if (!plymouth_running())
++ return 0;
++
++ /* try to connect or reconnect if sending a message */
++ if (m->plymouth_fd >= 0)
++ return 1;
++
++ m->plymouth_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
++ if (m->plymouth_fd < 0)
++ return log_warning_errno(errno, "Connection to plymouth socket failed: %m");
++
++ if (connect(m->plymouth_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
++ r = log_warning_errno(errno, "Couldn't connect to plymouth: %m");
++ goto fail;
++ }
++
++ r = sd_event_add_io(m->event, &m->plymouth_event_source, m->plymouth_fd, EPOLLIN, manager_plymouth_feedback_handler, m);
++ if (r < 0) {
++ log_warning_errno(r, "Can't listen to plymouth socket: %m");
++ goto fail;
++ }
++
++ return 1;
++
++fail:
++ manager_disconnect_plymouth(m);
++ return r;
++}
++
++static int plymouth_send_message(int plymouth_fd, const char *message, bool update) {
++ _cleanup_free_ char *packet = NULL;
++ int n;
++ char mode = 'M';
++
++ if (update)
++ mode = 'U';
++
++ if (asprintf(&packet, "%c\002%c%s%n", mode, (int) (strlen(message) + 1), message, &n) < 0)
++ return log_oom();
++
++ return loop_write(plymouth_fd, packet, n + 1, true);
++}
++
++static int manager_send_plymouth_message(Manager *m, const char *message) {
++ const char *plymouth_cancel_message = NULL, *l10n_cancel_message = NULL;
++ int r;
++
++ r = manager_connect_plymouth(m);
++ if (r < 0)
++ return r;
++ /* 0 means that plymouth isn't running, do not send any message yet */
++ else if (r == 0)
++ return 0;
++
++ if (!m->plymouth_cancel_sent) {
++
++ /* Indicate to plymouth that we listen to Ctrl+C */
++ r = loop_write(m->plymouth_fd, PLYMOUTH_REQUEST_KEY, sizeof(PLYMOUTH_REQUEST_KEY), true);
++ if (r < 0)
++ return log_warning_errno(r, "Can't send to plymouth cancel key: %m");
++
++ m->plymouth_cancel_sent = true;
++
++ l10n_cancel_message = _("Press Ctrl+C to cancel all filesystem checks in progress");
++ plymouth_cancel_message = strjoina("fsckd-cancel-msg:", l10n_cancel_message);
++
++ r = plymouth_send_message(m->plymouth_fd, plymouth_cancel_message, false);
++ if (r < 0)
++ log_warning_errno(r, "Can't send filesystem cancel message to plymouth: %m");
++
++ } else if (m->numdevices == 0) {
++
++ m->plymouth_cancel_sent = false;
++
++ r = plymouth_send_message(m->plymouth_fd, "", false);
++ if (r < 0)
++ log_warning_errno(r, "Can't clear plymouth filesystem cancel message: %m");
++ }
++
++ r = plymouth_send_message(m->plymouth_fd, message, true);
++ if (r < 0)
++ return log_warning_errno(r, "Couldn't send \"%s\" to plymouth: %m", message);
++
++ return 0;
++}
++
++static int manager_update_global_progress(Manager *m) {
++ _cleanup_free_ char *console_message = NULL;
++ _cleanup_free_ char *fsck_message = NULL;
++ int current_numdevices = 0, r;
++ double current_percent = 100;
++
++ /* get the overall percentage */
++ LIST_FOREACH(clients, current, m->clients) {
++ current_numdevices++;
++
++ /* right now, we only keep the minimum % of all fsckd processes. We could in the future trying to be
++ linear, but max changes and corresponds to the pass. We have all the informations into fsckd
++ already if we can treat that in a smarter way. */
++ current_percent = MIN(current_percent, current->percent);
++ }
++
++ /* update if there is anything user-visible to update */
++ if (fabs(current_percent - m->percent) > 0.001 || current_numdevices != m->numdevices) {
++ m->numdevices = current_numdevices;
++ m->percent = current_percent;
++
++ if (asprintf(&console_message,
++ ngettext("Checking in progress on %d disk (%3.1f%% complete)",
++ "Checking in progress on %d disks (%3.1f%% complete)", m->numdevices),
++ m->numdevices, m->percent) < 0)
++ return -ENOMEM;
++
++ if (asprintf(&fsck_message, "fsckd:%d:%3.1f:%s", m->numdevices, m->percent, console_message) < 0)
++ return -ENOMEM;
++
++ r = manager_write_console(m, console_message);
++ if (r < 0)
++ return r;
++
++ /* try to connect to plymouth and send message */
++ r = manager_send_plymouth_message(m, fsck_message);
++ if (r < 0)
++ return r;
++ }
++ return 0;
++}
++
++static int client_progress_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
++ Client *client = userdata;
++ char line[LINE_MAX];
++ Manager *m;
++
++ assert(client);
++ m = client->manager;
++
++ /* check first if we need to cancel this client */
++ if (m->cancel_requested)
++ client_request_cancel(client);
++
++ while (fgets(line, sizeof(line), client->fsck_f) != NULL) {
++ int pass;
++ size_t cur, max;
++ _cleanup_free_ char *device = NULL, *old_device_id = NULL;
++
++ if (sscanf(line, "%i %zu %zu %ms", &pass, &cur, &max, &device) == 4) {
++ if (!client->device_name) {
++ client->device_name = strdup(device);
++ if (!client->device_name) {
++ log_oom();
++ continue;
++ }
++ old_device_id = client->device_id;
++ client->device_id = strdup(device);
++ if (!client->device_id) {
++ log_oom();
++ client->device_id = old_device_id;
++ old_device_id = NULL;
++ continue;
++ }
++ }
++ client->pass = pass;
++ client->cur = cur;
++ client->max = max;
++ client->bad_input = false;
++ client->percent = compute_percent(client->pass, client->cur, client->max);
++ log_debug("Getting progress for %s (%zu, %zu, %d) : %3.1f%%", client->device_id,
++ client->cur, client->max, client->pass, client->percent);
++ } else {
++ if (errno == ENOMEM) {
++ log_oom();
++ continue;
++ }
++
++ /* if previous input was already garbage, kick it off from progress report */
++ if (client->bad_input) {
++ log_warning("Closing connection on incorrect input of fsck connection for %s", client->device_id);
++ client_free(client);
++ manager_update_global_progress(m);
++ return 0;
++ }
++ client->bad_input = true;
++ }
++
++ }
++
++ if (feof(client->fsck_f)) {
++ log_debug("Fsck client %s disconnected", client->device_id);
++ client_free(client);
++ }
++
++ manager_update_global_progress(m);
++ return 0;
++}
++
++static int manager_new_connection_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
++ _cleanup_(client_freep) Client *c = NULL;
++ _cleanup_close_ int new_fsck_fd = -1;
++ _cleanup_fclose_ FILE *new_fsck_f = NULL;
++ struct ucred ucred = {};
++ Manager *m = userdata;
++ int r;
++
++ assert(m);
++
++ /* Initialize and list new clients */
++ new_fsck_fd = accept4(m->connection_fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
++ if (new_fsck_fd < 0) {
++ log_error_errno(errno, "Couldn't accept a new connection: %m");
++ return 0;
++ }
++
++ if (m->n_clients >= CLIENTS_MAX) {
++ log_error("Too many clients, refusing connection.");
++ return 0;
++ }
++
++
++ new_fsck_f = fdopen(new_fsck_fd, "r");
++ if (!new_fsck_f) {
++ log_error_errno(errno, "Couldn't fdopen new connection for fd %d: %m", new_fsck_fd);
++ return 0;
++ }
++ new_fsck_fd = -1;
++
++ r = getpeercred(fileno(new_fsck_f), &ucred);
++ if (r < 0) {
++ log_error_errno(r, "Couldn't get credentials for fsck: %m");
++ return 0;
++ }
++
++ c = new0(Client, 1);
++ if (!c) {
++ log_oom();
++ return 0;
++ }
++
++ c->fsck_pid = ucred.pid;
++ c->fsck_f = new_fsck_f;
++ new_fsck_f = NULL;
++
++ if (asprintf(&(c->device_id), "fd %d", fileno(c->fsck_f)) < 0) {
++ log_oom();
++ return 0;
++ }
++
++ r = sd_event_add_io(m->event, &c->event_source, fileno(c->fsck_f), EPOLLIN, client_progress_handler, c);
++ if (r < 0) {
++ log_oom();
++ return 0;
++ }
++
++ LIST_PREPEND(clients, m->clients, c);
++ m->n_clients++;
++ c->manager = m;
++
++ log_debug("New fsck client connected: %s", c->device_id);
++
++ /* only request the client to cancel now in case the request is dropped by the client (chance to recancel) */
++ if (m->cancel_requested)
++ client_request_cancel(c);
++
++ c = NULL;
++ return 0;
++}
++
++static Manager* manager_free(Manager *m) {
++ if (!m)
++ return NULL;
++
++ /* clear last line */
++ manager_write_console(m, NULL);
++
++ sd_event_source_unref(m->connection_event_source);
++ safe_close(m->connection_fd);
++
++ while (m->clients)
++ client_free(m->clients);
++
++ manager_disconnect_plymouth(m);
++
++ sd_event_unref(m->event);
++
++ return mfree(m);
++}
++
++static int manager_new(Manager **ret, int fd) {
++ _cleanup_(manager_freep) Manager *m = NULL;
++ int r;
++
++ assert(ret);
++
++ m = new0(Manager, 1);
++ if (!m)
++ return -ENOMEM;
++
++ m->plymouth_fd = -1;
++ m->connection_fd = fd;
++ m->percent = 100;
++
++ r = sd_event_default(&m->event);
++ if (r < 0)
++ return r;
++
++ if (access("/run/systemd/show-status", F_OK) >= 0)
++ m->show_status_console = true;
++
++ r = sd_event_add_io(m->event, &m->connection_event_source, fd, EPOLLIN, manager_new_connection_handler, m);
++ if (r < 0)
++ return r;
++
++ *ret = m;
++ m = NULL;
++
++ return 0;
++}
++
++static int run_event_loop_with_timeout(Manager *m, usec_t timeout) {
++ int r, code;
++ sd_event *e = m->event;
++
++ assert(e);
++
++ for (;;) {
++ r = sd_event_get_state(e);
++ if (r < 0)
++ return r;
++ if (r == SD_EVENT_FINISHED)
++ break;
++
++ r = sd_event_run(e, timeout);
++ if (r < 0)
++ return r;
++
++ /* Exit if we reached the idle timeout and no more clients are
++ connected. If there is still an fsck process running but
++ simply slow to send us progress updates, exiting would mean
++ that this fsck process receives SIGPIPE resulting in an
++ aborted file system check. */
++ if (r == 0 && m->n_clients == 0) {
++ sd_event_exit(e, 0);
++ break;
++ }
++ }
++
++ r = sd_event_get_exit_code(e, &code);
++ if (r < 0)
++ return r;
++
++ return code;
++}
++
++static void help(void) {
++ printf("%s [OPTIONS...]\n\n"
++ "Capture fsck progress and forward one stream to plymouth\n\n"
++ " -h --help Show this help\n"
++ " --version Show package version\n",
++ program_invocation_short_name);
++}
++
++static int parse_argv(int argc, char *argv[]) {
++
++ enum {
++ ARG_VERSION = 0x100,
++ ARG_ROOT,
++ };
++
++ static const struct option options[] = {
++ { "help", no_argument, NULL, 'h' },
++ { "version", no_argument, NULL, ARG_VERSION },
++ {}
++ };
++
++ int c;
++
++ assert(argc >= 0);
++ assert(argv);
++
++ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
++ switch (c) {
++
++ case 'h':
++ help();
++ return 0;
++
++ case ARG_VERSION:
++ version();
++ return 0;
++
++ case '?':
++ return -EINVAL;
++
++ default:
++ assert_not_reached();
++ }
++
++ if (optind < argc) {
++ log_error("Extraneous arguments");
++ return -EINVAL;
++ }
++
++ return 1;
++}
++
++int main(int argc, char *argv[]) {
++ _cleanup_(manager_freep) Manager *m = NULL;
++ int fd = -1;
++ int r, n;
++
++ log_set_target(LOG_TARGET_AUTO);
++ log_parse_environment();
++ log_open();
++ init_gettext();
++
++ r = parse_argv(argc, argv);
++ if (r <= 0)
++ goto finish;
++
++ n = sd_listen_fds(0);
++ if (n > 1) {
++ log_error("Too many file descriptors received.");
++ r = -EINVAL;
++ goto finish;
++ } else if (n == 1)
++ fd = SD_LISTEN_FDS_START + 0;
++ else {
++ fd = make_socket_fd(LOG_DEBUG, FSCKD_SOCKET_PATH, SOCK_STREAM, SOCK_CLOEXEC);
++ if (fd < 0) {
++ r = log_error_errno(fd, "Couldn't create listening socket fd on %s: %m", FSCKD_SOCKET_PATH);
++ goto finish;
++ }
++ }
++
++ r = manager_new(&m, fd);
++ if (r < 0) {
++ log_error_errno(r, "Failed to allocate manager: %m");
++ goto finish;
++ }
++
++ r = run_event_loop_with_timeout(m, IDLE_TIME_SECONDS * USEC_PER_SEC);
++ if (r < 0) {
++ log_error_errno(r, "Failed to run event loop: %m");
++ goto finish;
++ }
++
++ sd_event_get_exit_code(m->event, &r);
++
++finish:
++ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
++}
+diff --git a/units/meson.build b/units/meson.build
+index 25e9209..8d3bef3 100644
+--- a/units/meson.build
++++ b/units/meson.build
+@@ -113,6 +113,7 @@ units = [
+ ['systemd-exit.service', ''],
+ ['systemd-firstboot.service', 'ENABLE_FIRSTBOOT',
+ 'sysinit.target.wants/'],
++ ['systemd-fsckd.socket', ''],
+ ['systemd-halt.service', ''],
+ ['systemd-homed-activate.service', 'ENABLE_HOMED'],
+ ['systemd-initctl.socket', 'HAVE_SYSV_COMPAT',
+@@ -194,6 +195,7 @@ in_units = [
+ ['systemd-pstore.service', 'ENABLE_PSTORE'],
+ ['systemd-fsck-root.service', ''],
+ ['systemd-fsck@.service', ''],
++ ['systemd-fsckd.service', ''],
+ ['systemd-hibernate-resume@.service', 'ENABLE_HIBERNATE'],
+ ['systemd-hibernate.service', 'ENABLE_HIBERNATE'],
+ ['systemd-hybrid-sleep.service', 'ENABLE_HIBERNATE'],
+diff --git a/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in
+index 8378df8..4b1cd43 100644
+--- a/units/systemd-fsck-root.service.in
++++ b/units/systemd-fsck-root.service.in
+@@ -13,6 +13,8 @@ Documentation=man:systemd-fsck-root.service(8)
+ DefaultDependencies=no
+ Conflicts=shutdown.target
+ Before=local-fs.target shutdown.target
++Wants=systemd-fsckd.socket
++After=systemd-fsckd.socket
+ ConditionPathIsReadWrite=!/
+ OnFailure=emergency.target
+ OnFailureJobMode=replace-irreversibly
+diff --git a/units/systemd-fsck@.service.in b/units/systemd-fsck@.service.in
+index 06b91ae..de0b767 100644
+--- a/units/systemd-fsck@.service.in
++++ b/units/systemd-fsck@.service.in
+@@ -13,7 +13,8 @@ Documentation=man:systemd-fsck@.service(8)
+ DefaultDependencies=no
+ BindsTo=%i.device
+ Conflicts=shutdown.target
+-After=%i.device systemd-fsck-root.service local-fs-pre.target
++Wants=systemd-fsckd.socket
++After=%i.device systemd-fsck-root.service local-fs-pre.target systemd-fsckd.socket
+ Before=systemd-quotacheck.service shutdown.target
+
+ [Service]
+diff --git a/units/systemd-fsckd.service.in b/units/systemd-fsckd.service.in
+new file mode 100644
+index 0000000..f075b66
+--- /dev/null
++++ b/units/systemd-fsckd.service.in
+@@ -0,0 +1,17 @@
++# This file is part of systemd.
++#
++# systemd is free software; you can redistribute it and/or modify it
++# under the terms of the GNU Lesser General Public License as published by
++# the Free Software Foundation; either version 2.1 of the License, or
++# (at your option) any later version.
++
++[Unit]
++Description=File System Check Daemon to report status
++Documentation=man:systemd-fsckd.service(8)
++DefaultDependencies=no
++Requires=systemd-fsckd.socket
++Before=shutdown.target
++
++[Service]
++ExecStart={{ROOTLIBEXECDIR}}/systemd-fsckd
++StandardOutput=journal+console
+diff --git a/units/systemd-fsckd.socket b/units/systemd-fsckd.socket
+new file mode 100644
+index 0000000..61fec97
+--- /dev/null
++++ b/units/systemd-fsckd.socket
+@@ -0,0 +1,15 @@
++# This file is part of systemd.
++#
++# systemd is free software; you can redistribute it and/or modify it
++# under the terms of the GNU Lesser General Public License as published by
++# the Free Software Foundation; either version 2.1 of the License, or
++# (at your option) any later version.
++
++[Unit]
++Description=fsck to fsckd communication Socket
++Documentation=man:systemd-fsckd.service(8) man:systemd-fsck@.service(8) man:systemd-fsck-root.service(8)
++DefaultDependencies=no
++
++[Socket]
++ListenStream=/run/systemd/fsck.progress
++SocketMode=0600
diff --git a/debian/patches/debian/systemctl-do-not-shutdown-immediately-on-scheduled-shutdo.patch b/debian/patches/debian/systemctl-do-not-shutdown-immediately-on-scheduled-shutdo.patch
new file mode 100644
index 0000000..f157e45
--- /dev/null
+++ b/debian/patches/debian/systemctl-do-not-shutdown-immediately-on-scheduled-shutdo.patch
@@ -0,0 +1,34 @@
+From: Ioanna Alifieraki <ioanna-maria.alifieraki@canonical.com>
+Date: Thu, 17 Dec 2020 14:52:07 +0000
+Subject: systemctl: do not shutdown immediately on scheduled shutdown
+
+When, for whatever reason, a scheduled shutdown fails to be set, systemd
+will proceed with immediate shutdown without allowing the user to react.
+This is counterintuitive because when a scheduled shutdown is issued,
+it means the user wants to shutdown at a specified time in the future,
+not immediately. This patch prevents the immediate shutdown and informs
+the user that no action will be taken.
+
+Fixes: #17575
+---
+ src/systemctl/systemctl-compat-halt.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/systemctl/systemctl-compat-halt.c b/src/systemctl/systemctl-compat-halt.c
+index 8a0e4e6..7eeec9a 100644
+--- a/src/systemctl/systemctl-compat-halt.c
++++ b/src/systemctl/systemctl-compat-halt.c
+@@ -148,9 +148,11 @@ int halt_main(void) {
+
+ if (arg_force == 0) {
+ /* always try logind first */
+- if (arg_when > 0)
++ if (arg_when > 0) {
+ r = logind_schedule_shutdown();
+- else {
++ if (r < 0)
++ return r;
++ } else {
+ r = logind_check_inhibitors(arg_action);
+ if (r < 0)
+ return r;
diff --git a/debian/patches/debian/udev-drop-SystemCallArchitectures-native-from-systemd-ude.patch b/debian/patches/debian/udev-drop-SystemCallArchitectures-native-from-systemd-ude.patch
new file mode 100644
index 0000000..5ad154b
--- /dev/null
+++ b/debian/patches/debian/udev-drop-SystemCallArchitectures-native-from-systemd-ude.patch
@@ -0,0 +1,25 @@
+From: Michael Biebl <biebl@debian.org>
+Date: Tue, 19 Nov 2019 09:10:23 +0100
+Subject: udev: drop SystemCallArchitectures=native from systemd-udevd.service
+
+We can't really control what helper programs are run from other udev
+rules. E.g. running i386 binaries under amd64 is a valid use case and
+should not trigger a SIGSYS failure.
+
+Closes: #869719
+---
+ units/systemd-udevd.service.in | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in
+index e9dbe85..22ca8b9 100644
+--- a/units/systemd-udevd.service.in
++++ b/units/systemd-udevd.service.in
+@@ -37,7 +37,6 @@ RestrictSUIDSGID=yes
+ SystemCallFilter=@system-service @module @raw-io bpf
+ SystemCallFilter=~@clock
+ SystemCallErrorNumber=EPERM
+-SystemCallArchitectures=native
+ LockPersonality=yes
+ IPAddressDeny=any
+ {{SERVICE_WATCHDOG}}
diff --git a/debian/patches/p11kit-switch-to-dlopen.patch b/debian/patches/p11kit-switch-to-dlopen.patch
new file mode 100644
index 0000000..b22bf58
--- /dev/null
+++ b/debian/patches/p11kit-switch-to-dlopen.patch
@@ -0,0 +1,743 @@
+From: Luca Boccassi <bluca@debian.org>
+Date: Sat, 17 Dec 2022 01:33:46 +0000
+Subject: p11kit: switch to dlopen()
+
+---
+ meson.build | 2 +
+ src/shared/meson.build | 2 +-
+ src/shared/pkcs11-util.c | 215 ++++++++++++++++++++++++++++++++++------------
+ src/shared/pkcs11-util.h | 28 +++++-
+ src/test/meson.build | 4 +-
+ src/test/test-dlopen-so.c | 5 ++
+ test/test-functions | 6 +-
+ 7 files changed, 202 insertions(+), 60 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index 9de2309..27d95e7 100644
+--- a/meson.build
++++ b/meson.build
+@@ -1462,8 +1462,10 @@ if want_p11kit != 'false' and not skip_deps
+ version : '>= 0.23.3',
+ required : want_p11kit == 'true')
+ have = libp11kit.found()
++ libp11kit_cflags = libp11kit.partial_dependency(includes: true, compile_args: true)
+ else
+ have = false
++ libp11kit_cflags = []
+ libp11kit = []
+ endif
+ conf.set10('HAVE_P11KIT', have)
+diff --git a/src/shared/meson.build b/src/shared/meson.build
+index 3e2f327..9c47d2d 100644
+--- a/src/shared/meson.build
++++ b/src/shared/meson.build
+@@ -459,7 +459,7 @@ libshared_deps = [threads,
+ liblz4,
+ libmount,
+ libopenssl,
+- libp11kit,
++ libp11kit_cflags,
+ libpam,
+ librt,
+ libseccomp,
+diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c
+index 752a21d..5f5dbae 100644
+--- a/src/shared/pkcs11-util.c
++++ b/src/shared/pkcs11-util.c
+@@ -3,6 +3,7 @@
+ #include <fcntl.h>
+
+ #include "ask-password-api.h"
++#include "dlfcn-util.h"
+ #include "env-util.h"
+ #include "escape.h"
+ #include "fd-util.h"
+@@ -40,17 +41,59 @@ bool pkcs11_uri_valid(const char *uri) {
+
+ #if HAVE_P11KIT
+
++static void *p11kit_dl = NULL;
++
++char *(*sym_p11_kit_module_get_name)(CK_FUNCTION_LIST *module);
++void (*sym_p11_kit_modules_finalize_and_release)(CK_FUNCTION_LIST **modules);
++CK_FUNCTION_LIST **(*sym_p11_kit_modules_load_and_initialize)(int flags);
++const char *(*sym_p11_kit_strerror)(CK_RV rv);
++int (*sym_p11_kit_uri_format)(P11KitUri *uri, P11KitUriType uri_type, char **string);
++void (*sym_p11_kit_uri_free)(P11KitUri *uri);
++CK_ATTRIBUTE_PTR (*sym_p11_kit_uri_get_attributes)(P11KitUri *uri, CK_ULONG *n_attrs);
++CK_INFO_PTR (*sym_p11_kit_uri_get_module_info)(P11KitUri *uri);
++CK_SLOT_INFO_PTR (*sym_p11_kit_uri_get_slot_info)(P11KitUri *uri);
++CK_TOKEN_INFO_PTR (*sym_p11_kit_uri_get_token_info)(P11KitUri *uri);
++int (*sym_p11_kit_uri_match_token_info)(const P11KitUri *uri, const CK_TOKEN_INFO *token_info);
++const char *(*sym_p11_kit_uri_message)(int code);
++P11KitUri *(*sym_p11_kit_uri_new)(void);
++int (*sym_p11_kit_uri_parse)(const char *string, P11KitUriType uri_type, P11KitUri *uri);
++
++int dlopen_p11kit(void) {
++ return dlopen_many_sym_or_warn(
++ &p11kit_dl,
++ "libp11-kit.so.0", LOG_DEBUG,
++ DLSYM_ARG(p11_kit_module_get_name),
++ DLSYM_ARG(p11_kit_modules_finalize_and_release),
++ DLSYM_ARG(p11_kit_modules_load_and_initialize),
++ DLSYM_ARG(p11_kit_strerror),
++ DLSYM_ARG(p11_kit_uri_format),
++ DLSYM_ARG(p11_kit_uri_free),
++ DLSYM_ARG(p11_kit_uri_get_attributes),
++ DLSYM_ARG(p11_kit_uri_get_module_info),
++ DLSYM_ARG(p11_kit_uri_get_slot_info),
++ DLSYM_ARG(p11_kit_uri_get_token_info),
++ DLSYM_ARG(p11_kit_uri_match_token_info),
++ DLSYM_ARG(p11_kit_uri_message),
++ DLSYM_ARG(p11_kit_uri_new),
++ DLSYM_ARG(p11_kit_uri_parse));
++}
++
+ int uri_from_string(const char *p, P11KitUri **ret) {
+- _cleanup_(p11_kit_uri_freep) P11KitUri *uri = NULL;
++ _cleanup_(sym_p11_kit_uri_freep) P11KitUri *uri = NULL;
++ int r;
+
+ assert(p);
+ assert(ret);
+
+- uri = p11_kit_uri_new();
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
++ uri = sym_p11_kit_uri_new();
+ if (!uri)
+ return -ENOMEM;
+
+- if (p11_kit_uri_parse(p, P11_KIT_URI_FOR_ANY, uri) != P11_KIT_URI_OK)
++ if (sym_p11_kit_uri_parse(p, P11_KIT_URI_FOR_ANY, uri) != P11_KIT_URI_OK)
+ return -EINVAL;
+
+ *ret = TAKE_PTR(uri);
+@@ -62,11 +105,14 @@ P11KitUri *uri_from_module_info(const CK_INFO *info) {
+
+ assert(info);
+
+- uri = p11_kit_uri_new();
++ if (dlopen_p11kit() < 0)
++ return NULL;
++
++ uri = sym_p11_kit_uri_new();
+ if (!uri)
+ return NULL;
+
+- *p11_kit_uri_get_module_info(uri) = *info;
++ *sym_p11_kit_uri_get_module_info(uri) = *info;
+ return uri;
+ }
+
+@@ -75,11 +121,14 @@ P11KitUri *uri_from_slot_info(const CK_SLOT_INFO *slot_info) {
+
+ assert(slot_info);
+
+- uri = p11_kit_uri_new();
++ if (dlopen_p11kit() < 0)
++ return NULL;
++
++ uri = sym_p11_kit_uri_new();
+ if (!uri)
+ return NULL;
+
+- *p11_kit_uri_get_slot_info(uri) = *slot_info;
++ *sym_p11_kit_uri_get_slot_info(uri) = *slot_info;
+ return uri;
+ }
+
+@@ -88,11 +137,14 @@ P11KitUri *uri_from_token_info(const CK_TOKEN_INFO *token_info) {
+
+ assert(token_info);
+
+- uri = p11_kit_uri_new();
++ if (dlopen_p11kit() < 0)
++ return NULL;
++
++ uri = sym_p11_kit_uri_new();
+ if (!uri)
+ return NULL;
+
+- *p11_kit_uri_get_token_info(uri) = *token_info;
++ *sym_p11_kit_uri_get_token_info(uri) = *token_info;
+ return uri;
+ }
+
+@@ -184,15 +236,20 @@ int pkcs11_token_login_by_pin(
+ size_t pin_size) {
+
+ CK_RV rv;
++ int r;
+
+ assert(m);
+ assert(token_info);
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ if (FLAGS_SET(token_info->flags, CKF_PROTECTED_AUTHENTICATION_PATH)) {
+ rv = m->C_Login(session, CKU_USER, NULL, 0);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
++ "Failed to log into security token '%s': %s", token_label, sym_p11_kit_strerror(rv));
+
+ log_info("Successfully logged into security token '%s' via protected authentication path.", token_label);
+ return 0;
+@@ -217,7 +274,7 @@ int pkcs11_token_login_by_pin(
+ "PIN has been locked, please reset PIN of security token '%s'.", token_label);
+ if (!IN_SET(rv, CKR_PIN_INCORRECT, CKR_PIN_LEN_RANGE))
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
++ "Failed to log into security token '%s': %s", token_label, sym_p11_kit_strerror(rv));
+
+ return log_notice_errno(SYNTHETIC_ERRNO(ENOLCK),
+ "PIN for token '%s' is incorrect, please try again.",
+@@ -239,7 +296,7 @@ int pkcs11_token_login(
+ char **ret_used_pin) {
+
+ _cleanup_free_ char *token_uri_string = NULL, *token_uri_escaped = NULL, *id = NULL, *token_label = NULL;
+- _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL;
++ _cleanup_(sym_p11_kit_uri_freep) P11KitUri *token_uri = NULL;
+ CK_TOKEN_INFO updated_token_info;
+ int uri_result, r;
+ CK_RV rv;
+@@ -247,6 +304,10 @@ int pkcs11_token_login(
+ assert(m);
+ assert(token_info);
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ token_label = pkcs11_token_label(token_info);
+ if (!token_label)
+ return log_oom();
+@@ -255,9 +316,9 @@ int pkcs11_token_login(
+ if (!token_uri)
+ return log_oom();
+
+- uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
++ uri_result = sym_p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
+ if (uri_result != P11_KIT_URI_OK)
+- return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
++ return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result));
+
+ r = pkcs11_token_login_by_pin(m, session, token_info, token_label, /* pin= */ NULL, 0);
+ if (r == 0 && ret_used_pin)
+@@ -336,7 +397,7 @@ int pkcs11_token_login(
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+ "Failed to acquire updated security token information for slot %lu: %s",
+- slotid, p11_kit_strerror(rv));
++ slotid, sym_p11_kit_strerror(rv));
+
+ token_info = &updated_token_info;
+ }
+@@ -357,12 +418,17 @@ int pkcs11_token_find_x509_certificate(
+ CK_ATTRIBUTE *attributes = NULL;
+ CK_OBJECT_HANDLE objects[2];
+ CK_RV rv, rv2;
++ int r;
+
+ assert(m);
+ assert(search_uri);
+ assert(ret_object);
+
+- attributes = p11_kit_uri_get_attributes(search_uri, &n_attributes);
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
++ attributes = sym_p11_kit_uri_get_attributes(search_uri, &n_attributes);
+ for (a = 0; a < n_attributes; a++) {
+
+ /* We use the URI's included match attributes, but make them more strict. This allows users
+@@ -435,16 +501,16 @@ int pkcs11_token_find_x509_certificate(
+ rv = m->C_FindObjectsInit(session, attributes, n_attributes);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to initialize object find call: %s", p11_kit_strerror(rv));
++ "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv));
+
+ rv = m->C_FindObjects(session, objects, ELEMENTSOF(objects), &n_objects);
+ rv2 = m->C_FindObjectsFinal(session);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to find objects: %s", p11_kit_strerror(rv));
++ "Failed to find objects: %s", sym_p11_kit_strerror(rv));
+ if (rv2 != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to finalize object find call: %s", p11_kit_strerror(rv));
++ "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv));
+ if (n_objects == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+ "Failed to find selected X509 certificate on token.");
+@@ -472,11 +538,16 @@ int pkcs11_token_read_x509_certificate(
+ _cleanup_(X509_freep) X509 *x509 = NULL;
+ X509_NAME *name = NULL;
+ const unsigned char *p;
++ int r;
++
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
+
+ rv = m->C_GetAttributeValue(session, object, &attribute, 1);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to read X.509 certificate size off token: %s", p11_kit_strerror(rv));
++ "Failed to read X.509 certificate size off token: %s", sym_p11_kit_strerror(rv));
+
+ buffer = malloc(attribute.ulValueLen);
+ if (!buffer)
+@@ -487,7 +558,7 @@ int pkcs11_token_read_x509_certificate(
+ rv = m->C_GetAttributeValue(session, object, &attribute, 1);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to read X.509 certificate data off token: %s", p11_kit_strerror(rv));
++ "Failed to read X.509 certificate data off token: %s", sym_p11_kit_strerror(rv));
+
+ p = attribute.pValue;
+ x509 = d2i_X509(NULL, &p, attribute.ulValueLen);
+@@ -521,12 +592,17 @@ int pkcs11_token_find_private_key(
+ CK_ATTRIBUTE *attributes = NULL;
+ CK_OBJECT_HANDLE objects[2];
+ CK_RV rv, rv2;
++ int r;
+
+ assert(m);
+ assert(search_uri);
+ assert(ret_object);
+
+- attributes = p11_kit_uri_get_attributes(search_uri, &n_attributes);
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
++ attributes = sym_p11_kit_uri_get_attributes(search_uri, &n_attributes);
+ for (a = 0; a < n_attributes; a++) {
+
+ /* We use the URI's included match attributes, but make them more strict. This allows users
+@@ -625,16 +701,16 @@ int pkcs11_token_find_private_key(
+ rv = m->C_FindObjectsInit(session, attributes, n_attributes);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to initialize object find call: %s", p11_kit_strerror(rv));
++ "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv));
+
+ rv = m->C_FindObjects(session, objects, ELEMENTSOF(objects), &n_objects);
+ rv2 = m->C_FindObjectsFinal(session);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to find objects: %s", p11_kit_strerror(rv));
++ "Failed to find objects: %s", sym_p11_kit_strerror(rv));
+ if (rv2 != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to finalize object find call: %s", p11_kit_strerror(rv));
++ "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv));
+ if (n_objects == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+ "Failed to find selected private key suitable for decryption on token.");
+@@ -661,6 +737,7 @@ int pkcs11_token_decrypt_data(
+ _cleanup_(erase_and_freep) CK_BYTE *dbuffer = NULL;
+ CK_ULONG dbuffer_size = 0;
+ CK_RV rv;
++ int r;
+
+ assert(m);
+ assert(encrypted_data);
+@@ -668,10 +745,14 @@ int pkcs11_token_decrypt_data(
+ assert(ret_decrypted_data);
+ assert(ret_decrypted_data_size);
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ rv = m->C_DecryptInit(session, (CK_MECHANISM*) &mechanism, object);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to initialize decryption on security token: %s", p11_kit_strerror(rv));
++ "Failed to initialize decryption on security token: %s", sym_p11_kit_strerror(rv));
+
+ dbuffer_size = encrypted_data_size; /* Start with something reasonable */
+ dbuffer = malloc(dbuffer_size);
+@@ -690,7 +771,7 @@ int pkcs11_token_decrypt_data(
+ }
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to decrypt key on security token: %s", p11_kit_strerror(rv));
++ "Failed to decrypt key on security token: %s", sym_p11_kit_strerror(rv));
+
+ log_info("Successfully decrypted key with security token.");
+
+@@ -710,6 +791,10 @@ int pkcs11_token_acquire_rng(
+
+ assert(m);
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ /* While we are at it, let's read some RNG data from the PKCS#11 token and pass it to the kernel
+ * random pool. This should be cheap if we are talking to the device already. Note that we don't
+ * credit any entropy, since we don't know about the quality of the pkcs#11 token's RNG. Why bother
+@@ -726,7 +811,7 @@ int pkcs11_token_acquire_rng(
+ rv = m->C_GenerateRandom(session, buffer, rps);
+ if (rv != CKR_OK)
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+- "Failed to generate RNG data on security token: %s", p11_kit_strerror(rv));
++ "Failed to generate RNG data on security token: %s", sym_p11_kit_strerror(rv));
+
+ r = random_write_entropy(-1, buffer, rps, false);
+ if (r < 0)
+@@ -762,7 +847,7 @@ static int token_process(
+ rv = m->C_OpenSession(slotid, CKF_SERIAL_SESSION, NULL, NULL, &session);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+- "Failed to create session for security token '%s': %s", token_label, p11_kit_strerror(rv));
++ "Failed to create session for security token '%s': %s", token_label, sym_p11_kit_strerror(rv));
+
+ if (callback)
+ r = callback(m, session, slotid, slot_info, token_info, search_uri, userdata);
+@@ -771,7 +856,7 @@ static int token_process(
+
+ rv = m->C_CloseSession(session);
+ if (rv != CKR_OK)
+- log_warning("Failed to close session on PKCS#11 token, ignoring: %s", p11_kit_strerror(rv));
++ log_warning("Failed to close session on PKCS#11 token, ignoring: %s", sym_p11_kit_strerror(rv));
+
+ return r;
+ }
+@@ -783,21 +868,25 @@ static int slot_process(
+ pkcs11_find_token_callback_t callback,
+ void *userdata) {
+
+- _cleanup_(p11_kit_uri_freep) P11KitUri* slot_uri = NULL, *token_uri = NULL;
++ _cleanup_(sym_p11_kit_uri_freep) P11KitUri* slot_uri = NULL, *token_uri = NULL;
+ _cleanup_free_ char *token_uri_string = NULL;
+ CK_TOKEN_INFO token_info;
+ CK_SLOT_INFO slot_info;
+- int uri_result;
++ int uri_result, r;
+ CK_RV rv;
+
+ assert(m);
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ /* We return -EAGAIN for all failures we can attribute to a specific slot in some way, so that the
+ * caller might try other slots before giving up. */
+
+ rv = m->C_GetSlotInfo(slotid, &slot_info);
+ if (rv != CKR_OK) {
+- log_warning("Failed to acquire slot info for slot %lu, ignoring slot: %s", slotid, p11_kit_strerror(rv));
++ log_warning("Failed to acquire slot info for slot %lu, ignoring slot: %s", slotid, sym_p11_kit_strerror(rv));
+ return -EAGAIN;
+ }
+
+@@ -808,9 +897,9 @@ static int slot_process(
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *slot_uri_string = NULL;
+
+- uri_result = p11_kit_uri_format(slot_uri, P11_KIT_URI_FOR_ANY, &slot_uri_string);
++ uri_result = sym_p11_kit_uri_format(slot_uri, P11_KIT_URI_FOR_ANY, &slot_uri_string);
+ if (uri_result != P11_KIT_URI_OK) {
+- log_warning("Failed to format slot URI, ignoring slot: %s", p11_kit_uri_message(uri_result));
++ log_warning("Failed to format slot URI, ignoring slot: %s", sym_p11_kit_uri_message(uri_result));
+ return -EAGAIN;
+ }
+
+@@ -822,7 +911,7 @@ static int slot_process(
+ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+ "Token not present in slot, ignoring.");
+ } else if (rv != CKR_OK) {
+- log_warning("Failed to acquire token info for slot %lu, ignoring slot: %s", slotid, p11_kit_strerror(rv));
++ log_warning("Failed to acquire token info for slot %lu, ignoring slot: %s", slotid, sym_p11_kit_strerror(rv));
+ return -EAGAIN;
+ }
+
+@@ -830,13 +919,13 @@ static int slot_process(
+ if (!token_uri)
+ return log_oom();
+
+- uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
++ uri_result = sym_p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
+ if (uri_result != P11_KIT_URI_OK) {
+- log_warning("Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
++ log_warning("Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result));
+ return -EAGAIN;
+ }
+
+- if (search_uri && !p11_kit_uri_match_token_info(search_uri, &token_info))
++ if (search_uri && !sym_p11_kit_uri_match_token_info(search_uri, &token_info))
+ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+ "Found non-matching token with URI %s.",
+ token_uri_string);
+@@ -859,8 +948,8 @@ static int module_process(
+ pkcs11_find_token_callback_t callback,
+ void *userdata) {
+
++ _cleanup_(sym_p11_kit_uri_freep) P11KitUri* module_uri = NULL;
+ _cleanup_free_ char *name = NULL, *module_uri_string = NULL;
+- _cleanup_(p11_kit_uri_freep) P11KitUri* module_uri = NULL;
+ _cleanup_free_ CK_SLOT_ID *slotids = NULL;
+ CK_ULONG n_slotids = 0;
+ int uri_result;
+@@ -871,11 +960,15 @@ static int module_process(
+
+ assert(m);
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ /* We ignore most errors from modules here, in order to skip over faulty modules: one faulty module
+ * should not have the effect that we don't try the others anymore. We indicate such per-module
+ * failures with -EAGAIN, which let's the caller try the next module. */
+
+- name = p11_kit_module_get_name(m);
++ name = sym_p11_kit_module_get_name(m);
+ if (!name)
+ return log_oom();
+
+@@ -883,7 +976,7 @@ static int module_process(
+
+ rv = m->C_GetInfo(&info);
+ if (rv != CKR_OK) {
+- log_warning("Failed to get info on PKCS#11 module, ignoring module: %s", p11_kit_strerror(rv));
++ log_warning("Failed to get info on PKCS#11 module, ignoring module: %s", sym_p11_kit_strerror(rv));
+ return -EAGAIN;
+ }
+
+@@ -891,9 +984,9 @@ static int module_process(
+ if (!module_uri)
+ return log_oom();
+
+- uri_result = p11_kit_uri_format(module_uri, P11_KIT_URI_FOR_ANY, &module_uri_string);
++ uri_result = sym_p11_kit_uri_format(module_uri, P11_KIT_URI_FOR_ANY, &module_uri_string);
+ if (uri_result != P11_KIT_URI_OK) {
+- log_warning("Failed to format module URI, ignoring module: %s", p11_kit_uri_message(uri_result));
++ log_warning("Failed to format module URI, ignoring module: %s", sym_p11_kit_uri_message(uri_result));
+ return -EAGAIN;
+ }
+
+@@ -901,7 +994,7 @@ static int module_process(
+
+ rv = pkcs11_get_slot_list_malloc(m, &slotids, &n_slotids);
+ if (rv != CKR_OK) {
+- log_warning("Failed to get slot list, ignoring module: %s", p11_kit_strerror(rv));
++ log_warning("Failed to get slot list, ignoring module: %s", sym_p11_kit_strerror(rv));
+ return -EAGAIN;
+ }
+ if (n_slotids == 0)
+@@ -927,10 +1020,14 @@ int pkcs11_find_token(
+ pkcs11_find_token_callback_t callback,
+ void *userdata) {
+
+- _cleanup_(p11_kit_modules_finalize_and_releasep) CK_FUNCTION_LIST **modules = NULL;
+- _cleanup_(p11_kit_uri_freep) P11KitUri *search_uri = NULL;
++ _cleanup_(sym_p11_kit_modules_finalize_and_releasep) CK_FUNCTION_LIST **modules = NULL;
++ _cleanup_(sym_p11_kit_uri_freep) P11KitUri *search_uri = NULL;
+ int r;
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ /* Execute the specified callback for each matching token found. If nothing is found returns
+ * -EAGAIN. Logs about all errors, except for EAGAIN, which the caller has to log about. */
+
+@@ -940,7 +1037,7 @@ int pkcs11_find_token(
+ return log_error_errno(r, "Failed to parse PKCS#11 URI '%s': %m", pkcs11_uri);
+ }
+
+- modules = p11_kit_modules_load_and_initialize(0);
++ modules = sym_p11_kit_modules_load_and_initialize(0);
+ if (!modules)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize pkcs11 modules");
+
+@@ -1068,13 +1165,17 @@ static int list_callback(
+ void *userdata) {
+
+ _cleanup_free_ char *token_uri_string = NULL, *token_label = NULL, *token_manufacturer_id = NULL, *token_model = NULL;
+- _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL;
++ _cleanup_(sym_p11_kit_uri_freep) P11KitUri *token_uri = NULL;
+ Table *t = userdata;
+ int uri_result, r;
+
+ assert(slot_info);
+ assert(token_info);
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ /* We only care about hardware devices here with a token inserted. Let's filter everything else
+ * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during
+ * enumeration we'll filter those, since software tokens are typically the system certificate store
+@@ -1098,9 +1199,9 @@ static int list_callback(
+ if (!token_uri)
+ return log_oom();
+
+- uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
++ uri_result = sym_p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
+ if (uri_result != P11_KIT_URI_OK)
+- return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
++ return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result));
+
+ r = table_add_many(
+ t,
+@@ -1154,13 +1255,17 @@ static int auto_callback(
+ P11KitUri *uri,
+ void *userdata) {
+
+- _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL;
++ _cleanup_(sym_p11_kit_uri_freep) P11KitUri *token_uri = NULL;
+ char **t = userdata;
+- int uri_result;
++ int uri_result, r;
+
+ assert(slot_info);
+ assert(token_info);
+
++ r = dlopen_p11kit();
++ if (r < 0)
++ return r;
++
+ if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT))
+ return -EAGAIN;
+
+@@ -1172,9 +1277,9 @@ static int auto_callback(
+ if (!token_uri)
+ return log_oom();
+
+- uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, t);
++ uri_result = sym_p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, t);
+ if (uri_result != P11_KIT_URI_OK)
+- return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
++ return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result));
+
+ return 0;
+ }
+diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h
+index 7c88848..5bc23c1 100644
+--- a/src/shared/pkcs11-util.h
++++ b/src/shared/pkcs11-util.h
+@@ -16,14 +16,30 @@
+ bool pkcs11_uri_valid(const char *uri);
+
+ #if HAVE_P11KIT
++
++extern char *(*sym_p11_kit_module_get_name)(CK_FUNCTION_LIST *module);
++extern void (*sym_p11_kit_modules_finalize_and_release)(CK_FUNCTION_LIST **modules);
++extern CK_FUNCTION_LIST **(*sym_p11_kit_modules_load_and_initialize)(int flags);
++extern const char *(*sym_p11_kit_strerror)(CK_RV rv);
++extern int (*sym_p11_kit_uri_format)(P11KitUri *uri, P11KitUriType uri_type, char **string);
++extern void (*sym_p11_kit_uri_free)(P11KitUri *uri);
++extern CK_ATTRIBUTE_PTR (*sym_p11_kit_uri_get_attributes)(P11KitUri *uri, CK_ULONG *n_attrs);
++extern CK_INFO_PTR (*sym_p11_kit_uri_get_module_info)(P11KitUri *uri);
++extern CK_SLOT_INFO_PTR (*sym_p11_kit_uri_get_slot_info)(P11KitUri *uri);
++extern CK_TOKEN_INFO_PTR (*sym_p11_kit_uri_get_token_info)(P11KitUri *uri);
++extern int (*sym_p11_kit_uri_match_token_info)(const P11KitUri *uri, const CK_TOKEN_INFO *token_info);
++extern const char *(*sym_p11_kit_uri_message)(int code);
++extern P11KitUri *(*sym_p11_kit_uri_new)(void);
++extern int (*sym_p11_kit_uri_parse)(const char *string, P11KitUriType uri_type, P11KitUri *uri);
++
+ int uri_from_string(const char *p, P11KitUri **ret);
+
+ P11KitUri *uri_from_module_info(const CK_INFO *info);
+ P11KitUri *uri_from_slot_info(const CK_SLOT_INFO *slot_info);
+ P11KitUri *uri_from_token_info(const CK_TOKEN_INFO *token_info);
+
+-DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(P11KitUri*, p11_kit_uri_free, NULL);
+-DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(CK_FUNCTION_LIST**, p11_kit_modules_finalize_and_release, NULL);
++DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(P11KitUri*, sym_p11_kit_uri_free, NULL);
++DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(CK_FUNCTION_LIST**, sym_p11_kit_modules_finalize_and_release, NULL);
+
+ CK_RV pkcs11_get_slot_list_malloc(CK_FUNCTION_LIST *m, CK_SLOT_ID **ret_slotids, CK_ULONG *ret_n_slotids);
+
+@@ -74,6 +90,14 @@ int pkcs11_crypt_device_callback(
+ P11KitUri *uri,
+ void *userdata);
+
++int dlopen_p11kit(void);
++
++#else
++
++static inline int dlopen_p11kit(void) {
++ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "p11kit support is not compiled in.");
++}
++
+ #endif
+
+ typedef struct {
+diff --git a/src/test/meson.build b/src/test/meson.build
+index 2a4dfe2..082566b 100644
+--- a/src/test/meson.build
++++ b/src/test/meson.build
+@@ -74,7 +74,9 @@ tests += [
+ [],
+ core_includes],
+
+- [files('test-dlopen-so.c')],
++ [files('test-dlopen-so.c'),
++ [],
++ libp11kit_cflags],
+
+ [files('test-job-type.c'),
+ [libcore,
+diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c
+index 85dbb81..55728c2 100644
+--- a/src/test/test-dlopen-so.c
++++ b/src/test/test-dlopen-so.c
+@@ -11,6 +11,7 @@
+ #include "macro.h"
+ #include "main-func.h"
+ #include "pcre2-util.h"
++#include "pkcs11-util.h"
+ #include "pwquality-util.h"
+ #include "qrcode-util.h"
+ #include "tests.h"
+@@ -60,6 +61,10 @@ static int run(int argc, char **argv) {
+ assert_se(dlopen_pcre2() >= 0);
+ #endif
+
++#if HAVE_P11KIT
++ assert_se(dlopen_p11kit() >= 0);
++#endif
++
+ return 0;
+ }
+
+diff --git a/test/test-functions b/test/test-functions
+index 73fbef8..0ba7ce2 100644
+--- a/test/test-functions
++++ b/test/test-functions
+@@ -1386,7 +1386,7 @@ install_missing_libraries() {
+ local lib path
+ # A number of dependencies is now optional via dlopen, so the install
+ # script will not pick them up, since it looks at linkage.
+- for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw xkbcommon; do
++ for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw xkbcommon p11-kit-1; do
+ ddebug "Searching for $lib via pkg-config"
+ if pkg-config --exists "$lib"; then
+ path="$(pkg-config --variable=libdir "$lib")"
+@@ -1398,6 +1398,10 @@ install_missing_libraries() {
+ if ! [[ ${lib} =~ ^lib ]]; then
+ lib="lib${lib}"
+ fi
++ # p11-kit-1's .so doesn't have the API level in the name
++ if [[ ${lib} =~ p11-kit-1$ ]]; then
++ lib="libp11-kit"
++ fi
+ # Some pkg-config files are broken and give out the wrong paths
+ # (eg: libcryptsetup), so just ignore them
+ inst_libs "${path}/${lib}.so" || true
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..661f0c4
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,20 @@
+p11kit-switch-to-dlopen.patch
+debian/Use-Debian-specific-config-files.patch
+debian/Bring-tmpfiles.d-tmp.conf-in-line-with-Debian-defaul.patch
+debian/Make-run-lock-tmpfs-an-API-fs.patch
+debian/Add-support-for-TuxOnIce-hibernation.patch
+debian/Re-enable-journal-forwarding-to-syslog.patch
+debian/Don-t-enable-audit-by-default.patch
+debian/Only-start-logind-if-dbus-is-installed.patch
+debian/fsckd-daemon-for-inter-fsckd-communication.patch
+debian/Skip-filesystem-check-if-already-done-by-the-initram.patch
+debian/Revert-core-one-step-back-again-for-nspawn-we-actual.patch
+debian/Revert-core-set-RLIMIT_CORE-to-unlimited-by-default.patch
+debian/Let-graphical-session-pre.target-be-manually-started.patch
+debian/deny-list-upstream-test-25.patch
+debian/deny-list-upstream-test-02-ppc64el.patch
+debian/udev-drop-SystemCallArchitectures-native-from-systemd-ude.patch
+debian/Move-sysusers.d-sysctl.d-binfmt.d-modules-load.d-back-to-.patch
+debian/systemctl-do-not-shutdown-immediately-on-scheduled-shutdo.patch
+debian/Downgrade-a-couple-of-warnings-to-debug.patch
+debian/Skip-flaky-test_resolved_domain_restricted_dns-in-network.patch