From 1abbeecfa4b0d6d176beddb7d0f09518a37d4ce1 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 03 2016 06:13:11 +0000 Subject: import systemd-219-30.el7 --- diff --git a/SOURCES/0258-run-synchronously-wait-until-the-scope-unit-we-creat.patch b/SOURCES/0258-run-synchronously-wait-until-the-scope-unit-we-creat.patch index 125a175..2634ba1 100644 --- a/SOURCES/0258-run-synchronously-wait-until-the-scope-unit-we-creat.patch +++ b/SOURCES/0258-run-synchronously-wait-until-the-scope-unit-we-creat.patch @@ -1,4 +1,4 @@ -From 18d515aeb3a2007fa0a762b9b9658f489d4b403d Mon Sep 17 00:00:00 2001 +From 5532bedf8ef456f02fdec62d46bc1be65cdfde30 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 28 Apr 2015 12:21:31 +0200 Subject: [PATCH] run: synchronously wait until the scope unit we create is @@ -11,7 +11,7 @@ short-running (such as an invocation to /bin/true). https://bugs.freedesktop.org/show_bug.cgi?id=86520 Cherry-picked from: de158ed22db60e3a6654557fa4aa72f7248550af -Resolves: #1283192 +Resolves: #1272368 --- src/libsystemd/sd-bus/bus-util.c | 10 ++++++++++ src/libsystemd/sd-bus/bus-util.h | 1 + diff --git a/SOURCES/0259-device-rework-how-we-enter-tentative-state.patch b/SOURCES/0259-device-rework-how-we-enter-tentative-state.patch index 5d3e8d6..b866e07 100644 --- a/SOURCES/0259-device-rework-how-we-enter-tentative-state.patch +++ b/SOURCES/0259-device-rework-how-we-enter-tentative-state.patch @@ -1,4 +1,4 @@ -From 960ea6ae7a9e2aca3594318ab893f7d5383e46b6 Mon Sep 17 00:00:00 2001 +From ff6c50a1451e0e8fdca72039a0a00ebb0a20ba6c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Apr 2015 12:29:05 +0200 Subject: [PATCH] device: rework how we enter tentative state diff --git a/SOURCES/0260-core-Do-not-bind-a-mount-unit-to-a-device-if-it-was-.patch b/SOURCES/0260-core-Do-not-bind-a-mount-unit-to-a-device-if-it-was-.patch index ac334ba..c1a9ea1 100644 --- a/SOURCES/0260-core-Do-not-bind-a-mount-unit-to-a-device-if-it-was-.patch +++ b/SOURCES/0260-core-Do-not-bind-a-mount-unit-to-a-device-if-it-was-.patch @@ -1,4 +1,4 @@ -From c81de449d57bc563be7b4d4d53d07de28adcaa9b Mon Sep 17 00:00:00 2001 +From 75b183700853e616362cf2f22831e1e9dc8a5515 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 24 Nov 2015 09:41:26 +0100 Subject: [PATCH] core: Do not bind a mount unit to a device, if it was from diff --git a/SOURCES/0261-logind-set-RemoveIPC-no-by-default.patch b/SOURCES/0261-logind-set-RemoveIPC-no-by-default.patch index 1094ebd..bce797f 100644 --- a/SOURCES/0261-logind-set-RemoveIPC-no-by-default.patch +++ b/SOURCES/0261-logind-set-RemoveIPC-no-by-default.patch @@ -1,4 +1,4 @@ -From b4d12e023a1418e850ec96616739e7be1d71c4f5 Mon Sep 17 00:00:00 2001 +From 07cda5adb4ccecc6208b9fc85f4ea3ed8dece47d Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Thu, 26 Nov 2015 14:14:55 +0100 Subject: [PATCH] logind: set RemoveIPC=no by default diff --git a/SOURCES/0262-sysv-generator-follow-symlinks-in-etc-rc.d-init.d.patch b/SOURCES/0262-sysv-generator-follow-symlinks-in-etc-rc.d-init.d.patch index b048273..e435f0e 100644 --- a/SOURCES/0262-sysv-generator-follow-symlinks-in-etc-rc.d-init.d.patch +++ b/SOURCES/0262-sysv-generator-follow-symlinks-in-etc-rc.d-init.d.patch @@ -1,4 +1,4 @@ -From 25dc202140f4daa18faeae11e26e9e16e8dae84e Mon Sep 17 00:00:00 2001 +From 7374770f790080b677f504075ba9659230e11226 Mon Sep 17 00:00:00 2001 From: Lukas Nykryn Date: Fri, 11 Sep 2015 16:23:07 +0200 Subject: [PATCH] sysv-generator: follow symlinks in /etc/rc.d/init.d @@ -11,7 +11,7 @@ On rhel-based distributions you can use alternatives --initscript instread of symlink, but this is not usable for other distributions. Cherry-picked from: 7b729f8686a83b24f3d9a891cde1c -Resolves: #1288005 +Resolves: #1285492 --- src/sysv-generator/sysv-generator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SOURCES/0263-man-RemoveIPC-is-set-to-no-on-rhel.patch b/SOURCES/0263-man-RemoveIPC-is-set-to-no-on-rhel.patch deleted file mode 100644 index 32b3385..0000000 --- a/SOURCES/0263-man-RemoveIPC-is-set-to-no-on-rhel.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 931ad3c2c253b40cb2c8eef8876b962e8f2d1072 Mon Sep 17 00:00:00 2001 -From: Lukas Nykryn -Date: Thu, 10 Dec 2015 09:34:34 +0100 -Subject: [PATCH] man: RemoveIPC is set to no on rhel - -RHEL-only - -Related: #1284588 ---- - man/logind.conf.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/man/logind.conf.xml b/man/logind.conf.xml -index d02d573..54651f0 100644 ---- a/man/logind.conf.xml -+++ b/man/logind.conf.xml -@@ -276,7 +276,7 @@ - memory and message queues, as well as POSIX shared memory and - message queues. Note that IPC objects of the root user are - excluded from the effect of this setting. Defaults to -- yes. -+ no. - - - diff --git a/SOURCES/0263-sysv-generator-test-always-log-to-console.patch b/SOURCES/0263-sysv-generator-test-always-log-to-console.patch new file mode 100644 index 0000000..b6f4daf --- /dev/null +++ b/SOURCES/0263-sysv-generator-test-always-log-to-console.patch @@ -0,0 +1,28 @@ +From a714212703b3fe5f2a27773602cabbc4ab53da15 Mon Sep 17 00:00:00 2001 +From: Martin Pitt +Date: Mon, 15 Jun 2015 08:59:44 +0200 +Subject: [PATCH] sysv-generator test: always log to console + +Set $SYSTEMD_LOG_TARGET so that the output always goes to stdout/stderr. This +fixes running the test as root, as that logged to the journal previously. + +https://github.com/systemd/systemd/issues/195 + +Cherry-picked from: 6b7d32add4733a83f86e18bb86f914037a6688b7 +Resolves: #1279034 +--- + test/sysv-generator-test.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py +index e716d70..1537864 100644 +--- a/test/sysv-generator-test.py ++++ b/test/sysv-generator-test.py +@@ -60,6 +60,7 @@ class SysvGeneratorTest(unittest.TestCase): + ''' + env = os.environ.copy() + env['SYSTEMD_LOG_LEVEL'] = 'debug' ++ env['SYSTEMD_LOG_TARGET'] = 'console' + env['SYSTEMD_SYSVINIT_PATH'] = self.init_d_dir + env['SYSTEMD_SYSVRCND_PATH'] = self.rcnd_dir + env['SYSTEMD_UNIT_PATH'] = self.unit_dir diff --git a/SOURCES/0264-makefile-disable-udev-tests.patch b/SOURCES/0264-makefile-disable-udev-tests.patch deleted file mode 100644 index dcf9d8e..0000000 --- a/SOURCES/0264-makefile-disable-udev-tests.patch +++ /dev/null @@ -1,27 +0,0 @@ -From c79d960c9cf769e913c6824363c0f2f7f257762e Mon Sep 17 00:00:00 2001 -From: Lukas Nykryn -Date: Thu, 10 Dec 2015 11:08:19 +0100 -Subject: [PATCH] makefile: disable udev tests - -RHEL-only ---- - Makefile.am | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/Makefile.am b/Makefile.am -index 887e70a..2645f66 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -3785,9 +3785,9 @@ hwdb-remove-hook: - endif - - # ------------------------------------------------------------------------------ --TESTS += \ -- test/udev-test.pl \ -- $(NULL) -+#TESTS += \ -+# test/udev-test.pl \ -+# $(NULL) - - if HAVE_PYTHON - TESTS += \ diff --git a/SOURCES/0264-man-RemoveIPC-is-set-to-no-on-rhel.patch b/SOURCES/0264-man-RemoveIPC-is-set-to-no-on-rhel.patch new file mode 100644 index 0000000..2a6d56c --- /dev/null +++ b/SOURCES/0264-man-RemoveIPC-is-set-to-no-on-rhel.patch @@ -0,0 +1,25 @@ +From 7602b4a03ef2b932ef3c22ce25d01a782074059f Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 10 Dec 2015 09:34:34 +0100 +Subject: [PATCH] man: RemoveIPC is set to no on rhel + +RHEL-only + +Related: #1284588 +--- + man/logind.conf.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/logind.conf.xml b/man/logind.conf.xml +index d02d573..54651f0 100644 +--- a/man/logind.conf.xml ++++ b/man/logind.conf.xml +@@ -276,7 +276,7 @@ + memory and message queues, as well as POSIX shared memory and + message queues. Note that IPC objects of the root user are + excluded from the effect of this setting. Defaults to +- yes. ++ no. + + + diff --git a/SOURCES/0265-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch b/SOURCES/0265-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch new file mode 100644 index 0000000..7933126 --- /dev/null +++ b/SOURCES/0265-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch @@ -0,0 +1,28 @@ +From 14eaa63230a16a32f49db74d4b0d78247874ccdd Mon Sep 17 00:00:00 2001 +From: Didier Roche +Date: Wed, 13 Jan 2016 12:49:57 +0100 +Subject: [PATCH] Avoid /tmp being mounted as tmpfs without the user's will + +Ensure PrivateTmp doesn't require tmpfs through tmp.mount, but rather +adds an After relationship. + +rhel-only + +Resolves: #1298109 +--- + src/core/unit.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index ae47a28..4fb2fd3 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -807,7 +807,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { + return 0; + + if (c->private_tmp) { +- r = unit_require_mounts_for(u, "/tmp"); ++ r = unit_add_dependency_by_name(u, UNIT_AFTER, "tmp.mount", NULL, true); + if (r < 0) + return r; + diff --git a/SOURCES/0265-sysv-generator-test-always-log-to-console.patch b/SOURCES/0265-sysv-generator-test-always-log-to-console.patch deleted file mode 100644 index b882f6a..0000000 --- a/SOURCES/0265-sysv-generator-test-always-log-to-console.patch +++ /dev/null @@ -1,27 +0,0 @@ -From dff573ed5425cad26370ce5f4dc95c859d58ee72 Mon Sep 17 00:00:00 2001 -From: Martin Pitt -Date: Mon, 15 Jun 2015 08:59:44 +0200 -Subject: [PATCH] sysv-generator test: always log to console - -Set $SYSTEMD_LOG_TARGET so that the output always goes to stdout/stderr. This -fixes running the test as root, as that logged to the journal previously. - -https://github.com/systemd/systemd/issues/195 - -Cherry-picked from: 6b7d32add4733a83f86e18bb86f914037a6688b7 ---- - test/sysv-generator-test.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py -index e716d70..1537864 100644 ---- a/test/sysv-generator-test.py -+++ b/test/sysv-generator-test.py -@@ -60,6 +60,7 @@ class SysvGeneratorTest(unittest.TestCase): - ''' - env = os.environ.copy() - env['SYSTEMD_LOG_LEVEL'] = 'debug' -+ env['SYSTEMD_LOG_TARGET'] = 'console' - env['SYSTEMD_SYSVINIT_PATH'] = self.init_d_dir - env['SYSTEMD_SYSVRCND_PATH'] = self.rcnd_dir - env['SYSTEMD_UNIT_PATH'] = self.unit_dir diff --git a/SOURCES/0266-test-sysv-generator-Check-for-network-online.target.patch b/SOURCES/0266-test-sysv-generator-Check-for-network-online.target.patch index 678699e..db2ca26 100644 --- a/SOURCES/0266-test-sysv-generator-Check-for-network-online.target.patch +++ b/SOURCES/0266-test-sysv-generator-Check-for-network-online.target.patch @@ -1,8 +1,9 @@ -From dc923c37bf23c035e510c241ff228e3e2f92c1ef Mon Sep 17 00:00:00 2001 +From e955c2298241b9a2957dd8d36c48cbfe0a108d49 Mon Sep 17 00:00:00 2001 From: Branislav Blaskovic Date: Sat, 7 Nov 2015 11:32:49 +0100 Subject: [PATCH] test sysv-generator: Check for network-online.target. +Resolves: #1279034 --- test/sysv-generator-test.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/SOURCES/0267-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch b/SOURCES/0267-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch deleted file mode 100644 index 4f06b24..0000000 --- a/SOURCES/0267-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 73d33e8e1b310c292dc92d26ca0cd7bfefa31852 Mon Sep 17 00:00:00 2001 -From: Didier Roche -Date: Wed, 13 Jan 2016 12:49:57 +0100 -Subject: [PATCH] Avoid /tmp being mounted as tmpfs without the user's will - -Ensure PrivateTmp doesn't require tmpfs through tmp.mount, but rather -adds an After relationship. - -rhel-only - -Resolves: #1298109 ---- - src/core/unit.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/core/unit.c b/src/core/unit.c -index ae47a28..4fb2fd3 100644 ---- a/src/core/unit.c -+++ b/src/core/unit.c -@@ -807,7 +807,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { - return 0; - - if (c->private_tmp) { -- r = unit_require_mounts_for(u, "/tmp"); -+ r = unit_add_dependency_by_name(u, UNIT_AFTER, "tmp.mount", NULL, true); - if (r < 0) - return r; - diff --git a/SOURCES/0267-makefile-disable-udev-tests.patch b/SOURCES/0267-makefile-disable-udev-tests.patch new file mode 100644 index 0000000..4379d44 --- /dev/null +++ b/SOURCES/0267-makefile-disable-udev-tests.patch @@ -0,0 +1,27 @@ +From 7da662710420fdcbf2691f4a82644332d18d4605 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 10 Dec 2015 11:08:19 +0100 +Subject: [PATCH] makefile: disable udev tests + +RHEL-only +--- + Makefile.am | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 887e70a..2645f66 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3785,9 +3785,9 @@ hwdb-remove-hook: + endif + + # ------------------------------------------------------------------------------ +-TESTS += \ +- test/udev-test.pl \ +- $(NULL) ++#TESTS += \ ++# test/udev-test.pl \ ++# $(NULL) + + if HAVE_PYTHON + TESTS += \ diff --git a/SOURCES/0268-arm-aarch64-detect-virt-check-dmi.patch b/SOURCES/0268-arm-aarch64-detect-virt-check-dmi.patch new file mode 100644 index 0000000..59389fd --- /dev/null +++ b/SOURCES/0268-arm-aarch64-detect-virt-check-dmi.patch @@ -0,0 +1,40 @@ +From a64e8d52d4058451e8b8d291db4cc276ee31d46d Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Mon, 9 Nov 2015 14:22:20 +0100 +Subject: [PATCH] arm/aarch64: detect-virt: check dmi + +ARM/AArch64 guests now have SMBIOS tables populated (when boot +with a late enough QEMU and a late enough AAVMF is used as the +bootloader). Furthermore, when booting ARM/AArch64 guests with +ACPI, the DT detection obviously no longer works, so we need +dmi detection. + +Cherry-picked from: 2ef8a4c4399dcb7b6fcaecd41f27377b584e9a4b +Resolves: #1278165 +--- + src/shared/virt.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/shared/virt.c b/src/shared/virt.c +index 54c4655..d3ce8dd 100644 +--- a/src/shared/virt.c ++++ b/src/shared/virt.c +@@ -29,7 +29,7 @@ + + static int detect_vm_cpuid(const char **_id) { + +- /* Both CPUID and DMI are x86 specific interfaces... */ ++ /* CPUID is an x86 specific interface. */ + #if defined(__i386__) || defined(__x86_64__) + + static const char cpuid_vendor_table[] = +@@ -139,8 +139,7 @@ static int detect_vm_devicetree(const char **_id) { + + static int detect_vm_dmi(const char **_id) { + +- /* Both CPUID and DMI are x86 specific interfaces... */ +-#if defined(__i386__) || defined(__x86_64__) ++#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) + + static const char *const dmi_vendors[] = { + "/sys/class/dmi/id/sys_vendor", diff --git a/SOURCES/0268-udev-fibre-channel-fix-NPIV-support.patch b/SOURCES/0268-udev-fibre-channel-fix-NPIV-support.patch deleted file mode 100644 index 5958e60..0000000 --- a/SOURCES/0268-udev-fibre-channel-fix-NPIV-support.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 41bcd014886cfd2bc4415f2c78668008963934a9 Mon Sep 17 00:00:00 2001 -From: Maurizio Lombardi -Date: Mon, 1 Feb 2016 14:44:22 +0100 -Subject: [PATCH] udev: fibre channel: fix NPIV support - -When using NPIV, you can create multiple virtual HBAs on top of the -physical one, this means that the physical N_Port can have multiple -port IDs associated to it. -Suppose a LUN is assigned to the physical HBA and to a virtual HBA, -in both cases the original code uses the ID of the physical HBA -to build the by-path link and udev will end up trying to create two by-path -links with the same name. - -This patch fixes the problem by using the port ID of the virtual HBA -whenever it detects that the device belongs to a virtual HBA, -otherwise it uses the port ID of the physical HBA. - -(cherry-picked from 155a760bcedd11b7f3b430350a46f10736286895) - -Resolves: #1266934 ---- - src/udev/udev-builtin-path_id.c | 27 ++++++++++++++++++++++++--- - 1 file changed, 24 insertions(+), 3 deletions(-) - -diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c -index 9ca6084..695ac7f 100644 ---- a/src/udev/udev-builtin-path_id.c -+++ b/src/udev/udev-builtin-path_id.c -@@ -92,6 +92,9 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s - static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { - struct udev *udev = udev_device_get_udev(parent); - struct udev_device *targetdev; -+ struct udev_device *rportdev; -+ struct udev_device *hostdev; -+ struct udev_device *vportdev; - struct udev_device *fcdev = NULL; - const char *port; - char *lun = NULL; -@@ -100,9 +103,27 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, - if (targetdev == NULL) - return NULL; - -- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); -- if (fcdev == NULL) -- return NULL; -+ rportdev = udev_device_get_parent(targetdev); -+ if (rportdev == NULL) -+ goto skip_npiv_check; -+ -+ hostdev = udev_device_get_parent(rportdev); -+ if (hostdev == NULL) -+ goto skip_npiv_check; -+ -+ vportdev = udev_device_get_parent(hostdev); -+ if (vportdev == NULL) -+ goto skip_npiv_check; -+ -+ fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev)); -+ -+skip_npiv_check: -+ if (fcdev == NULL) { -+ fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); -+ if (fcdev == NULL) -+ return NULL; -+ } -+ - port = udev_device_get_sysattr_value(fcdev, "port_name"); - if (port == NULL) { - parent = NULL; diff --git a/SOURCES/0269-ata_id-unreverse-WWN-identifier.patch b/SOURCES/0269-ata_id-unreverse-WWN-identifier.patch deleted file mode 100644 index 3f875a3..0000000 --- a/SOURCES/0269-ata_id-unreverse-WWN-identifier.patch +++ /dev/null @@ -1,43 +0,0 @@ -From af5732176cb192206f555a1c00dd5431a757367f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= -Date: Wed, 22 Jul 2015 00:23:47 -0400 -Subject: [PATCH] ata_id: unreverse WWN identifier - -An endianness conversion was lost in 6024a6e302bad6bcf073fa84a41a6123305dc845. -Restore it. Now ata_id and scsi_id output match. - -https://bugzilla.redhat.com/show_bug.cgi?id=1227503 - -Cherry-picked from: 01f61d331bb5038f0c877ac03c54333328b6ea28 -Resolves: #1308795 ---- - src/udev/ata_id/ata_id.c | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c -index b6f28c6..4adec44 100644 ---- a/src/udev/ata_id/ata_id.c -+++ b/src/udev/ata_id/ata_id.c -@@ -638,10 +638,20 @@ int main(int argc, char *argv[]) - * All other values are reserved. - */ - word = identify.wyde[108]; -- if ((word & 0xf000) == 0x5000) -+ if ((word & 0xf000) == 0x5000) { -+ uint64_t wwwn; -+ -+ wwwn = identify.wyde[108]; -+ wwwn <<= 16; -+ wwwn |= identify.wyde[109]; -+ wwwn <<= 16; -+ wwwn |= identify.wyde[110]; -+ wwwn <<= 16; -+ wwwn |= identify.wyde[111]; - printf("ID_WWN=0x%1$" PRIx64 "\n" - "ID_WWN_WITH_EXTENSION=0x%1$" PRIx64 "\n", -- identify.octa[108/4]); -+ wwwn); -+ } - - /* from Linux's include/linux/ata.h */ - if (identify.wyde[0] == 0x848a || diff --git a/SOURCES/0269-detect-virt-dmi-look-for-KVM.patch b/SOURCES/0269-detect-virt-dmi-look-for-KVM.patch new file mode 100644 index 0000000..b33108a --- /dev/null +++ b/SOURCES/0269-detect-virt-dmi-look-for-KVM.patch @@ -0,0 +1,40 @@ +From 795d7cadb7b49ae11e2544ce325779f8d5ec7526 Mon Sep 17 00:00:00 2001 +From: Andrew Jones +Date: Mon, 9 Nov 2015 14:29:09 +0100 +Subject: [PATCH] detect-virt: dmi: look for KVM + +Some guests (ARM, AArch64, x86-RHEL) have 'KVM' in the product name. +Look for that first in order to more precisely report "kvm" when +detecting a QEMU/KVM guest. Without this patch we report "qemu", +even if KVM acceleration is in use on ARM/AArch64 guests. + +I've only tested a backported version of this and the previous +patch on an AArch64 guest (which worked). Of course it would be +nice to get regression testing on all guest types that depend on +dmi done. + +Cherry-picked from: 3728dcde4542b7b2792d9ef0baeb742d82983b03 +Resolves: #1278165 +--- + src/shared/virt.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/shared/virt.c b/src/shared/virt.c +index d3ce8dd..55a6ca9 100644 +--- a/src/shared/virt.c ++++ b/src/shared/virt.c +@@ -142,12 +142,14 @@ static int detect_vm_dmi(const char **_id) { + #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) + + static const char *const dmi_vendors[] = { ++ "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */ + "/sys/class/dmi/id/sys_vendor", + "/sys/class/dmi/id/board_vendor", + "/sys/class/dmi/id/bios_vendor" + }; + + static const char dmi_vendor_table[] = ++ "KVM\0" "kvm\0" + "QEMU\0" "qemu\0" + /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ + "VMware\0" "vmware\0" diff --git a/SOURCES/0270-Fixup-WWN-bytes-for-big-endian-systems.patch b/SOURCES/0270-Fixup-WWN-bytes-for-big-endian-systems.patch deleted file mode 100644 index 932fd0e..0000000 --- a/SOURCES/0270-Fixup-WWN-bytes-for-big-endian-systems.patch +++ /dev/null @@ -1,26 +0,0 @@ -From e2236a77928842bbf092956f8fa1918f2b4f7b9b Mon Sep 17 00:00:00 2001 -From: Tom Lyon -Date: Mon, 21 Sep 2015 14:36:32 -0700 -Subject: [PATCH] Fixup WWN bytes for big-endian systems - -Cherry-picked from: cf22cddcfd07d10fecd7b03ef465e957054daec2 -Resolves: #1308795 ---- - src/udev/ata_id/ata_id.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c -index 4adec44..ef05fba 100644 ---- a/src/udev/ata_id/ata_id.c -+++ b/src/udev/ata_id/ata_id.c -@@ -485,6 +485,10 @@ int main(int argc, char *argv[]) - disk_identify_fixup_uint16(identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */ - disk_identify_fixup_uint16(identify.byte, 91); /* current APM values */ - disk_identify_fixup_uint16(identify.byte, 94); /* current AAM value */ -+ disk_identify_fixup_uint16(identify.byte, 108); /* wwn */ -+ disk_identify_fixup_uint16(identify.byte, 109); /* wwn */ -+ disk_identify_fixup_uint16(identify.byte, 110); /* wwn */ -+ disk_identify_fixup_uint16(identify.byte, 111); /* wwn */ - disk_identify_fixup_uint16(identify.byte, 128); /* device lock function */ - disk_identify_fixup_uint16(identify.byte, 217); /* nominal media rotation rate */ - memcpy(&id, identify.byte, sizeof id); diff --git a/SOURCES/0270-Revert-journald-turn-ForwardToSyslog-off-by-default.patch b/SOURCES/0270-Revert-journald-turn-ForwardToSyslog-off-by-default.patch new file mode 100644 index 0000000..499e9a7 --- /dev/null +++ b/SOURCES/0270-Revert-journald-turn-ForwardToSyslog-off-by-default.patch @@ -0,0 +1,54 @@ +From 1b8d3a9c51d5584b6f6e394592a83b43cfbc693d Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 25 Jan 2016 14:03:47 +0100 +Subject: [PATCH] Revert "journald: turn ForwardToSyslog= off by default" + +This reverts commit 46b131574fdd7d77c15a0919ca9010cad7aa6ac7. + +rhel-only + +Resolves: #1285642 +--- + 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 2cbe58b..c4f71e8 100644 +--- a/man/journald.conf.xml ++++ b/man/journald.conf.xml +@@ -302,7 +302,7 @@ + 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 ++ forwarding to syslog and wall is enabled. These settings may be + overridden at boot time with the kernel command line options + systemd.journald.forward_to_syslog=, + systemd.journald.forward_to_kmsg=, +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index f13147f..6a35ebb 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1470,6 +1470,7 @@ int server_init(Server *s) { + s->rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL; + s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST; + ++ s->forward_to_syslog = true; + s->forward_to_wall = true; + + s->max_file_usec = DEFAULT_MAX_FILE_USEC; +diff --git a/src/journal/journald.conf b/src/journal/journald.conf +index 47eefe9..3907dfb 100644 +--- a/src/journal/journald.conf ++++ b/src/journal/journald.conf +@@ -27,7 +27,7 @@ + #RuntimeMaxFileSize= + #MaxRetentionSec= + #MaxFileSec=1month +-#ForwardToSyslog=no ++#ForwardToSyslog=yes + #ForwardToKMsg=no + #ForwardToConsole=no + #ForwardToWall=yes diff --git a/SOURCES/0271-Revert-udev-fibre-channel-fix-NPIV-support.patch b/SOURCES/0271-Revert-udev-fibre-channel-fix-NPIV-support.patch deleted file mode 100644 index e9ab780..0000000 --- a/SOURCES/0271-Revert-udev-fibre-channel-fix-NPIV-support.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 3b9db589b168cef9c07ad63c8cc06950844bfd5b Mon Sep 17 00:00:00 2001 -From: Michal Sekletar -Date: Mon, 29 Feb 2016 16:33:38 +0100 -Subject: [PATCH] Revert "udev: fibre channel: fix NPIV support" - -This reverts commit 569d98e9caae425120bf28f6b440e6cc117abc0d. - -Related: #1266934 ---- - src/udev/udev-builtin-path_id.c | 27 +++------------------------ - 1 file changed, 3 insertions(+), 24 deletions(-) - -diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c -index 695ac7f..9ca6084 100644 ---- a/src/udev/udev-builtin-path_id.c -+++ b/src/udev/udev-builtin-path_id.c -@@ -92,9 +92,6 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s - static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { - struct udev *udev = udev_device_get_udev(parent); - struct udev_device *targetdev; -- struct udev_device *rportdev; -- struct udev_device *hostdev; -- struct udev_device *vportdev; - struct udev_device *fcdev = NULL; - const char *port; - char *lun = NULL; -@@ -103,27 +100,9 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, - if (targetdev == NULL) - return NULL; - -- rportdev = udev_device_get_parent(targetdev); -- if (rportdev == NULL) -- goto skip_npiv_check; -- -- hostdev = udev_device_get_parent(rportdev); -- if (hostdev == NULL) -- goto skip_npiv_check; -- -- vportdev = udev_device_get_parent(hostdev); -- if (vportdev == NULL) -- goto skip_npiv_check; -- -- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev)); -- --skip_npiv_check: -- if (fcdev == NULL) { -- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); -- if (fcdev == NULL) -- return NULL; -- } -- -+ fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); -+ if (fcdev == NULL) -+ return NULL; - port = udev_device_get_sysattr_value(fcdev, "port_name"); - if (port == NULL) { - parent = NULL; diff --git a/SOURCES/0271-terminal-util-when-resetting-terminals-don-t-wait-fo.patch b/SOURCES/0271-terminal-util-when-resetting-terminals-don-t-wait-fo.patch new file mode 100644 index 0000000..62276b3 --- /dev/null +++ b/SOURCES/0271-terminal-util-when-resetting-terminals-don-t-wait-fo.patch @@ -0,0 +1,75 @@ +From 067fbebee46a376c639c9369dcaf80004047414d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 3 Aug 2015 19:04:08 +0200 +Subject: [PATCH] terminal-util: when resetting terminals, don't wait for + carrier + +In case of non-CLOCAL lines (i.e. those with carrier detect configured) +we shouldnt wait for a carrier if all we try to do is reset the TTY. +Hence, whenever we open such a TTY pass O_NONBLOCK. + +Note that we continue to open ttys we intend to write to without +O_ONBLOCK, we only add it in cases we invoke ioctl()s or other terminal +operations without reading or writing to the device. + +Fixes #835. + +Cherry-picked from: 0a8b555ceb07ce916b9bd48782d1eb69a12f0f2e +Resolves: #1266745 +--- + src/shared/util.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 778c2b0..5092588 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -1713,7 +1713,7 @@ bool fstype_is_network(const char *fstype) { + int chvt(int vt) { + _cleanup_close_ int fd; + +- fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); ++ fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (fd < 0) + return -errno; + +@@ -1953,7 +1953,11 @@ finish: + int reset_terminal(const char *name) { + _cleanup_close_ int fd = -1; + +- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); ++ /* We open the terminal with O_NONBLOCK here, to ensure we ++ * don't block on carrier if this is a terminal with carrier ++ * configured. */ ++ ++ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (fd < 0) + return fd; + +@@ -2204,7 +2208,7 @@ int release_terminal(void) { + struct sigaction sa_old; + int r = 0; + +- fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC); ++ fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (fd < 0) + return -errno; + +@@ -4405,7 +4409,7 @@ int terminal_vhangup_fd(int fd) { + int terminal_vhangup(const char *name) { + _cleanup_close_ int fd; + +- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); ++ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (fd < 0) + return fd; + +@@ -4452,7 +4456,7 @@ int vt_disallocate(const char *name) { + return -EINVAL; + + /* Try to deallocate */ +- fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); ++ fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK); + if (fd < 0) + return fd; + diff --git a/SOURCES/0272-basic-terminal-util-introduce-SYSTEMD_COLORS-environ.patch b/SOURCES/0272-basic-terminal-util-introduce-SYSTEMD_COLORS-environ.patch new file mode 100644 index 0000000..e4546ec --- /dev/null +++ b/SOURCES/0272-basic-terminal-util-introduce-SYSTEMD_COLORS-environ.patch @@ -0,0 +1,154 @@ +From 9d67a3a2d4fd378ca04726c5eb5f31ee222c50e4 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 19 Jan 2016 10:17:19 +0100 +Subject: [PATCH] basic/terminal-util: introduce SYSTEMD_COLORS environment + variable + +... to determine if color output should be enabled. If the variable is not set, +fall back to using on_tty(). Also, rewrite existing code to use +colors_enabled() where appropriate. + +Cherry-picked from: 40c9fe4c0862114dab390c8ed16f78cf056b9140 +Resolves: #1247963 +--- + man/systemd.xml | 7 +++++++ + src/journal/journalctl.c | 2 +- + src/login/loginctl.c | 2 +- + src/machine/machinectl.c | 2 +- + src/shared/util.c | 13 +++++++++++++ + src/shared/util.h | 13 +++++++------ + src/systemctl/systemctl.c | 2 +- + 7 files changed, 31 insertions(+), 10 deletions(-) + +diff --git a/man/systemd.xml b/man/systemd.xml +index eb289f0..30005b1 100644 +--- a/man/systemd.xml ++++ b/man/systemd.xml +@@ -755,6 +755,13 @@ + + + ++ $SYSTEMD_COLORS ++ ++ Controls whether colorized output should be generated. ++ ++ ++ ++ + $LISTEN_PID + $LISTEN_FDS + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 8236d08..7058788 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -2140,7 +2140,7 @@ int main(int argc, char *argv[]) { + flags = + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH | +- on_tty() * OUTPUT_COLOR | ++ colors_enabled() * OUTPUT_COLOR | + arg_catalog * OUTPUT_CATALOG | + arg_utc * OUTPUT_UTC; + +diff --git a/src/login/loginctl.c b/src/login/loginctl.c +index 6c8a59e..8e3bfbe 100644 +--- a/src/login/loginctl.c ++++ b/src/login/loginctl.c +@@ -83,7 +83,7 @@ static OutputFlags get_output_flags(void) { + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH | + (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | +- on_tty() * OUTPUT_COLOR; ++ colors_enabled() * OUTPUT_COLOR; + } + + static int list_sessions(int argc, char *argv[], void *userdata) { +diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c +index f191070..ef1214a 100644 +--- a/src/machine/machinectl.c ++++ b/src/machine/machinectl.c +@@ -105,7 +105,7 @@ static OutputFlags get_output_flags(void) { + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH | + (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | +- on_tty() * OUTPUT_COLOR | ++ colors_enabled() * OUTPUT_COLOR | + !arg_quiet * OUTPUT_WARN_CUTOFF; + } + +diff --git a/src/shared/util.c b/src/shared/util.c +index 5092588..dc51852 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -8146,3 +8146,16 @@ char *shell_maybe_quote(const char *s) { + + return r; + } ++ ++bool colors_enabled(void) { ++ const char *colors; ++ ++ colors = getenv("SYSTEMD_COLORS"); ++ if (!colors) { ++ if (streq_ptr(getenv("TERM"), "dumb")) ++ return false; ++ return on_tty(); ++ } ++ ++ return parse_boolean(colors) != 0; ++} +diff --git a/src/shared/util.h b/src/shared/util.h +index 7ecfd85..b4a4a49 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -485,29 +485,30 @@ unsigned lines(void); + void columns_lines_cache_reset(int _unused_ signum); + + bool on_tty(void); ++bool colors_enabled(void); + + static inline const char *ansi_highlight(void) { +- return on_tty() ? ANSI_HIGHLIGHT_ON : ""; ++ return colors_enabled() ? ANSI_HIGHLIGHT_ON : ""; + } + + static inline const char *ansi_highlight_red(void) { +- return on_tty() ? ANSI_HIGHLIGHT_RED_ON : ""; ++ return colors_enabled() ? ANSI_HIGHLIGHT_RED_ON : ""; + } + + static inline const char *ansi_highlight_green(void) { +- return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : ""; ++ return colors_enabled() ? ANSI_HIGHLIGHT_GREEN_ON : ""; + } + + static inline const char *ansi_highlight_yellow(void) { +- return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : ""; ++ return colors_enabled() ? ANSI_HIGHLIGHT_YELLOW_ON : ""; + } + + static inline const char *ansi_highlight_blue(void) { +- return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : ""; ++ return colors_enabled() ? ANSI_HIGHLIGHT_BLUE_ON : ""; + } + + static inline const char *ansi_highlight_off(void) { +- return on_tty() ? ANSI_HIGHLIGHT_OFF : ""; ++ return colors_enabled() ? ANSI_HIGHLIGHT_OFF : ""; + } + + int files_same(const char *filea, const char *fileb); +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 89d0b3b..5d3a85f 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -197,7 +197,7 @@ static OutputFlags get_output_flags(void) { + arg_all * OUTPUT_SHOW_ALL | + arg_full * OUTPUT_FULL_WIDTH | + (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | +- on_tty() * OUTPUT_COLOR | ++ colors_enabled() * OUTPUT_COLOR | + !arg_quiet * OUTPUT_WARN_CUTOFF; + } + diff --git a/SOURCES/0272-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch b/SOURCES/0272-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch deleted file mode 100644 index 82e8f78..0000000 --- a/SOURCES/0272-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 77314a3851676724fa018d76a4136fba059082d4 Mon Sep 17 00:00:00 2001 -From: Mauricio Faria de Oliveira -Date: Tue, 23 Feb 2016 15:02:02 -0300 -Subject: [PATCH] udev: path-id: fibre channel NPIV - use fc_vport's port_name - -With the Fibre Channel NPIV (N_Port ID Virtualization) feature, -a single physical N_Port (e.g., PCI address) can have multiple -N_Port IDs (e.g., different fc_host nodes) - which can connect -to the same target LUN (e.g., fc_remote_port's port_name and -LUN number). - -Thus, in order to be unique, the device persistent path should -include the fc_vport's port_name (only if the fc_vport is used), -in addition to the already in use PCI address, fc_remote_port's -port_name and LUN number. - -The patch merges the 2 proposals submitted upstream, addressing -some problems with both: -- #2500 (don't replace the fc_rport's port_name with fc_vport's) -- #2665 (don't add a fc_host/fc_vport's port_name if not needed) - -Links -- https://github.com/systemd/systemd/pull/2500/ -- https://github.com/systemd/systemd/pull/2665/ - -Built, checked, tested on RHEL Server 7.1 with no regressions. - -With the patch, /dev/disk/by-path symlinks are created correctly, -and are unique, backward-compatible with the physical port case: -- physical port (no vport field) -- virtual ports (w/ vport field) - - # ls -l /dev/disk/by-path | grep 0001:09:00.0 - <...> pci-0001:09:00.0-fc-0x500507680b2255fe-lun-0 -> ../../sdh - <...> pci-0001:09:00.0-fc-0x500507680b2255ff-lun-0 -> ../../sdi - <...> pci-0001:09:00.0-vport-0x5001a4aaf00a6785-fc-0x500507680b2255fe-lun-0 -> ../../sde - <...> pci-0001:09:00.0-vport-0x5001a4aaf00a6785-fc-0x500507680b2255ff-lun-0 -> ../../sdd - <...> pci-0001:09:00.0-vport-0x5001a4ad99d8c2de-fc-0x500507680b2255fe-lun-0 -> ../../sdc - <...> pci-0001:09:00.0-vport-0x5001a4ad99d8c2de-fc-0x500507680b2255ff-lun-0 -> ../../sdb - -Accordingly w/ sysfs: - - # ls -ld /sys/block/sd* | grep host1 - <...> /sys/block/sdb -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-0/host3/rport-3:0-1/target3:0:0/3:0:0:0/block/sdb - <...> /sys/block/sdc -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-0/host3/rport-3:0-2/target3:0:1/3:0:1:0/block/sdc - <...> /sys/block/sdd -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-2/host5/rport-5:0-1/target5:0:0/5:0:0:0/block/sdd - <...> /sys/block/sde -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-2/host5/rport-5:0-2/target5:0:1/5:0:1:0/block/sde - <...> /sys/block/sdh -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/rport-1:0-3/target1:0:0/1:0:0:0/block/sdh - <...> /sys/block/sdi -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/rport-1:0-4/target1:0:1/1:0:1:0/block/sdi - -The symlinks still include the fc_remote_port's (target) port_name: - - # grep . /sys/class/fc_remote_ports/rport-{3:0-{1,2},5:0-{1,2},1:0-{3,4}}/port_name - /sys/class/fc_remote_ports/rport-3:0-1/port_name:0x500507680b2255ff - /sys/class/fc_remote_ports/rport-3:0-2/port_name:0x500507680b2255fe - /sys/class/fc_remote_ports/rport-5:0-1/port_name:0x500507680b2255ff - /sys/class/fc_remote_ports/rport-5:0-2/port_name:0x500507680b2255fe - /sys/class/fc_remote_ports/rport-1:0-3/port_name:0x500507680b2255fe - /sys/class/fc_remote_ports/rport-1:0-4/port_name:0x500507680b2255ff - -And now include the fc_vport's (virtual host) port_name *if* it's from a fc_vport: - - # grep . /sys/class/fc_host/host1/port_name /sys/class/fc_vports/vport-1:0-{0,2}/port_name - /sys/class/fc_host/host1/port_name:0x10000090fa8f0ebc - /sys/class/fc_vports/vport-1:0-0/port_name:0x5001a4ad99d8c2de - /sys/class/fc_vports/vport-1:0-2/port_name:0x5001a4aaf00a6785 - -Signed-off-by: Mauricio Faria de Oliveira -Reported-by: Srikanth B. Aithal - -Cherry-picked from: 6a3d3f9e5970cf982ac37c65d0b856146b675a12 -Resolves: #1266934 ---- - src/udev/udev-builtin-path_id.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c -index 9ca6084..3b72922 100644 ---- a/src/udev/udev-builtin-path_id.c -+++ b/src/udev/udev-builtin-path_id.c -@@ -92,7 +92,11 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s - static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { - struct udev *udev = udev_device_get_udev(parent); - struct udev_device *targetdev; -+ struct udev_device *rportdev; -+ struct udev_device *hostdev; -+ struct udev_device *vportdev; - struct udev_device *fcdev = NULL; -+ struct udev_device *fc_vportdev = NULL; - const char *port; - char *lun = NULL; - -@@ -113,6 +117,32 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, - path_prepend(path, "fc-%s-%s", port, lun); - if (lun) - free(lun); -+ -+ /* NPIV */ -+ rportdev = udev_device_get_parent(targetdev); -+ if (rportdev == NULL) -+ goto out; -+ -+ hostdev = udev_device_get_parent(rportdev); -+ if (hostdev == NULL) -+ goto out; -+ -+ vportdev = udev_device_get_parent(hostdev); -+ if (vportdev == NULL) -+ goto out; -+ -+ fc_vportdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev)); -+ if (fc_vportdev == NULL) -+ goto out; -+ -+ port = udev_device_get_sysattr_value(fc_vportdev, "port_name"); -+ if (port == NULL) -+ goto out_npiv; -+ -+ path_prepend(path, "vport-%s", port); -+ -+out_npiv: -+ udev_device_unref(fc_vportdev); - out: - udev_device_unref(fcdev); - return parent; diff --git a/SOURCES/0273-ask-password-don-t-abort-when-message-is-missing.patch b/SOURCES/0273-ask-password-don-t-abort-when-message-is-missing.patch new file mode 100644 index 0000000..2cd79fe --- /dev/null +++ b/SOURCES/0273-ask-password-don-t-abort-when-message-is-missing.patch @@ -0,0 +1,35 @@ +From 2737fab0dba5ed238b4e0e927139e46e4911e1b4 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 28 Jan 2016 16:01:51 +0100 +Subject: [PATCH] ask-password: don't abort when message is missing + +This was fixed in upstream in +e287086b8aa2558356af225a12d9bfea8e7d61ca +add support for caching passwords in the kernel keyring + +But we don't want that in rhel. + +rhel-only + +Resolves: #1261136 +--- + src/shared/ask-password-api.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c +index 0a61daf..19baa6b 100644 +--- a/src/shared/ask-password-api.c ++++ b/src/shared/ask-password-api.c +@@ -70,9 +70,11 @@ int ask_password_tty( + POLL_INOTIFY + }; + +- assert(message); + assert(_passphrase); + ++ if (!message) ++ message = "Password:"; ++ + if (flag_file) { + notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); + if (notify < 0) { diff --git a/SOURCES/0273-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch b/SOURCES/0273-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch deleted file mode 100644 index a7ee894..0000000 --- a/SOURCES/0273-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 92f17bb12a37fe9deb0868ef8c4a43696319e72e Mon Sep 17 00:00:00 2001 -From: Lukas Nykryn -Date: Thu, 25 Feb 2016 15:15:04 +0100 -Subject: [PATCH] rules: set SYSTEMD_READY=0 on - DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 only with ADD event - -The "SYSTEMD_READY=0" will cause automatic unmount -of mountpoint that is on top of such DM device -if this is used with multipath which sets -DM_UDEV_DISABLE_OTHER_RULES_FLAG in case -we have a CHANGE event thatcomes after DM multipath -device reload when one of the paths is down or up. - -See https://bugzilla.redhat.com/show_bug.cgi?id=1312011 - -RHEL-only -Cherry-picked from: 83a3642f617975d596b5001b1699c3d16773a6e5 -Resolves: #1312011 ---- - rules/99-systemd.rules.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in -index b66d727..a4f4bf3 100644 ---- a/rules/99-systemd.rules.in -+++ b/rules/99-systemd.rules.in -@@ -12,7 +12,7 @@ SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*|3270 - KERNEL=="vport*", TAG+="systemd" - - SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd" --SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" -+SUBSYSTEM=="block", KERNEL!="ram*", ACTION=="add", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" - - # Ignore encrypted devices with no identified superblock on it, since - # we are probably still calling mke2fs or mkswap on it. diff --git a/SOURCES/0274-Revert-journald-turn-ForwardToSyslog-off-by-default.patch b/SOURCES/0274-Revert-journald-turn-ForwardToSyslog-off-by-default.patch deleted file mode 100644 index ce7e24e..0000000 --- a/SOURCES/0274-Revert-journald-turn-ForwardToSyslog-off-by-default.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 298dd4f0bf734002a4fc7f51e5a46216017db2f6 Mon Sep 17 00:00:00 2001 -From: Lukas Nykryn -Date: Mon, 25 Jan 2016 14:03:47 +0100 -Subject: [PATCH] Revert "journald: turn ForwardToSyslog= off by default" - -This reverts commit 46b131574fdd7d77c15a0919ca9010cad7aa6ac7. - -rhel-only - -Resolves: #1285642 ---- - 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 2cbe58b..c4f71e8 100644 ---- a/man/journald.conf.xml -+++ b/man/journald.conf.xml -@@ -302,7 +302,7 @@ - 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 -+ forwarding to syslog and wall is enabled. These settings may be - overridden at boot time with the kernel command line options - systemd.journald.forward_to_syslog=, - systemd.journald.forward_to_kmsg=, -diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c -index f13147f..6a35ebb 100644 ---- a/src/journal/journald-server.c -+++ b/src/journal/journald-server.c -@@ -1470,6 +1470,7 @@ int server_init(Server *s) { - s->rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL; - s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST; - -+ s->forward_to_syslog = true; - s->forward_to_wall = true; - - s->max_file_usec = DEFAULT_MAX_FILE_USEC; -diff --git a/src/journal/journald.conf b/src/journal/journald.conf -index 47eefe9..3907dfb 100644 ---- a/src/journal/journald.conf -+++ b/src/journal/journald.conf -@@ -27,7 +27,7 @@ - #RuntimeMaxFileSize= - #MaxRetentionSec= - #MaxFileSec=1month --#ForwardToSyslog=no -+#ForwardToSyslog=yes - #ForwardToKMsg=no - #ForwardToConsole=no - #ForwardToWall=yes diff --git a/SOURCES/0274-sysv-generator-do-not-join-dependencies-on-one-line-.patch b/SOURCES/0274-sysv-generator-do-not-join-dependencies-on-one-line-.patch new file mode 100644 index 0000000..99ffbe7 --- /dev/null +++ b/SOURCES/0274-sysv-generator-do-not-join-dependencies-on-one-line-.patch @@ -0,0 +1,135 @@ +From 72b3ff75e786efa2c9b2fdfb50e46597434c5420 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 20 Jan 2016 15:16:32 +0100 +Subject: [PATCH] sysv-generator: do not join dependencies on one line, split + them + +If there is a lot of initscripts and dependencies between them we might +end generating After= (and similar) lines which are longer then LINE_MAX +and thus rejected by parser in systemd. + +Fixes #2099 + +Cherry-picked from: c584ffc0b75d4b9e9229bf1d8edb7d89562be3c1 +Resolves: #1288600 +--- + src/sysv-generator/sysv-generator.c | 44 ++++++++++--------------------------- + test/sysv-generator-test.py | 18 +++++++++++++-- + 2 files changed, 28 insertions(+), 34 deletions(-) + +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index 0a8a528..d60e75a 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -134,34 +134,14 @@ static int add_alias(const char *service, const char *alias) { + } + + static int generate_unit_file(SysvStub *s) { +- char **p; + _cleanup_fclose_ FILE *f = NULL; +- _cleanup_free_ char *unit = NULL; +- _cleanup_free_ char *before = NULL; +- _cleanup_free_ char *after = NULL; +- _cleanup_free_ char *wants = NULL; +- _cleanup_free_ char *conflicts = NULL; ++ const char *unit; ++ char **p; + int r; + +- before = strv_join(s->before, " "); +- if (!before) +- return log_oom(); +- +- after = strv_join(s->after, " "); +- if (!after) +- return log_oom(); +- +- wants = strv_join(s->wants, " "); +- if (!wants) +- return log_oom(); +- +- conflicts = strv_join(s->conflicts, " "); +- if (!conflicts) +- return log_oom(); ++ assert(s); + +- unit = strjoin(arg_dest, "/", s->name, NULL); +- if (!unit) +- return log_oom(); ++ unit = strjoina(arg_dest, "/", s->name); + + /* We might already have a symlink with the same name from a Provides:, + * or from backup files like /etc/init.d/foo.bak. Real scripts always win, +@@ -183,14 +163,14 @@ static int generate_unit_file(SysvStub *s) { + "Description=%s\n", + s->path, s->description); + +- if (!isempty(before)) +- fprintf(f, "Before=%s\n", before); +- if (!isempty(after)) +- fprintf(f, "After=%s\n", after); +- if (!isempty(wants)) +- fprintf(f, "Wants=%s\n", wants); +- if (!isempty(conflicts)) +- fprintf(f, "Conflicts=%s\n", conflicts); ++ STRV_FOREACH(p, s->before) ++ fprintf(f, "Before=%s\n", *p); ++ STRV_FOREACH(p, s->after) ++ fprintf(f, "After=%s\n", *p); ++ STRV_FOREACH(p, s->wants) ++ fprintf(f, "Wants=%s\n", *p); ++ STRV_FOREACH(p, s->conflicts) ++ fprintf(f, "Conflicts=%s\n", *p); + + fprintf(f, + "\n[Service]\n" +diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py +index 2060ad7..25a35da 100644 +--- a/test/sysv-generator-test.py ++++ b/test/sysv-generator-test.py +@@ -23,6 +23,7 @@ import subprocess + import tempfile + import shutil + from glob import glob ++import collections + + try: + from configparser import RawConfigParser +@@ -32,6 +33,12 @@ except ImportError: + + sysv_generator = os.path.join(os.environ.get('builddir', '.'), 'systemd-sysv-generator') + ++class MultiDict(collections.OrderedDict): ++ def __setitem__(self, key, value): ++ if isinstance(value, list) and key in self: ++ self[key].extend(value) ++ else: ++ super(MultiDict, self).__setitem__(key, value) + + class SysvGeneratorTest(unittest.TestCase): + def setUp(self): +@@ -77,7 +84,14 @@ class SysvGeneratorTest(unittest.TestCase): + for service in glob(self.out_dir + '/*.service'): + if os.path.islink(service): + continue +- cp = RawConfigParser() ++ try: ++ # for python3 we need here strict=False to parse multiple ++ # lines with the same key ++ cp = RawConfigParser(dict_type=MultiDict, strict=False) ++ except TypeError: ++ # RawConfigParser in python2 does not have the strict option ++ # but it allows multiple lines with the same key by default ++ cp = RawConfigParser(dict_type=MultiDict) + cp.optionxform = lambda o: o # don't lower-case option names + with open(service) as f: + cp.readfp(f) +@@ -215,7 +229,7 @@ class SysvGeneratorTest(unittest.TestCase): + s = self.run_generator()[1]['foo.service'] + self.assertEqual(set(s.options('Unit')), + set(['Documentation', 'SourcePath', 'Description', 'After'])) +- self.assertEqual(s.get('Unit', 'After'), 'nss-lookup.target rpcbind.target') ++ self.assertEqual(s.get('Unit', 'After').split(), ['nss-lookup.target', 'rpcbind.target']) + + def test_lsb_deps(self): + '''LSB header dependencies to other services''' diff --git a/SOURCES/0275-journal-fix-error-handling-when-compressing-journal-.patch b/SOURCES/0275-journal-fix-error-handling-when-compressing-journal-.patch deleted file mode 100644 index 286998e..0000000 --- a/SOURCES/0275-journal-fix-error-handling-when-compressing-journal-.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 4c82b9247b29f31814e7ee5f77c745db659e27ac Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Sat, 24 Oct 2015 13:17:54 +0200 -Subject: [PATCH] journal: fix error handling when compressing journal objects - -Let's make sure we handle compression errors properly, and don't -misunderstand an error for success. - -Also, let's actually compress things if lz4 is enabled. - -Fixes #1662. - -Cherry-picked from: d1afbcd22170e95c79261340071d376fe41fc3af -Resolves: #1292447 ---- - src/journal/journal-file.c | 12 +++++++----- - src/journal/journal-file.h | 5 +++++ - 2 files changed, 12 insertions(+), 5 deletions(-) - -diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c -index f500568..a8f92e2 100644 ---- a/src/journal/journal-file.c -+++ b/src/journal/journal-file.c -@@ -1051,23 +1051,25 @@ static int journal_file_append_data( - o->data.hash = htole64(hash); - - #if defined(HAVE_XZ) || defined(HAVE_LZ4) -- if (f->compress_xz && -- size >= COMPRESSION_SIZE_THRESHOLD) { -+ if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) { - size_t rsize; - - compression = compress_blob(data, size, o->data.payload, &rsize); - -- if (compression) { -+ if (compression >= 0) { - o->object.size = htole64(offsetof(Object, data.payload) + rsize); - o->object.flags |= compression; - - log_debug("Compressed data object %"PRIu64" -> %zu using %s", - size, rsize, object_compressed_to_string(compression)); -- } -+ } else -+ /* Compression didn't work, we don't really care why, let's continue without compression */ -+ compression = 0; -+ - } - #endif - -- if (!compression && size > 0) -+ if (compression == 0 && size > 0) - memcpy(o->data.payload, data, size); - - r = journal_file_link_data(f, o, p, hash); -diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h -index 403c8f7..0f29b09 100644 ---- a/src/journal/journal-file.h -+++ b/src/journal/journal-file.h -@@ -229,3 +229,8 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t * - int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to); - - bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec); -+ -+static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) { -+ assert(f); -+ return f->compress_xz || f->compress_lz4; -+} diff --git a/SOURCES/0275-udev-fibre-channel-fix-NPIV-support.patch b/SOURCES/0275-udev-fibre-channel-fix-NPIV-support.patch new file mode 100644 index 0000000..5258624 --- /dev/null +++ b/SOURCES/0275-udev-fibre-channel-fix-NPIV-support.patch @@ -0,0 +1,69 @@ +From 569d98e9caae425120bf28f6b440e6cc117abc0d Mon Sep 17 00:00:00 2001 +From: Maurizio Lombardi +Date: Mon, 1 Feb 2016 14:44:22 +0100 +Subject: [PATCH] udev: fibre channel: fix NPIV support + +When using NPIV, you can create multiple virtual HBAs on top of the +physical one, this means that the physical N_Port can have multiple +port IDs associated to it. +Suppose a LUN is assigned to the physical HBA and to a virtual HBA, +in both cases the original code uses the ID of the physical HBA +to build the by-path link and udev will end up trying to create two by-path +links with the same name. + +This patch fixes the problem by using the port ID of the virtual HBA +whenever it detects that the device belongs to a virtual HBA, +otherwise it uses the port ID of the physical HBA. + +(cherry-picked from 155a760bcedd11b7f3b430350a46f10736286895) + +Resolves: #1266934 +--- + src/udev/udev-builtin-path_id.c | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 9ca6084..695ac7f 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -92,6 +92,9 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s + static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; ++ struct udev_device *rportdev; ++ struct udev_device *hostdev; ++ struct udev_device *vportdev; + struct udev_device *fcdev = NULL; + const char *port; + char *lun = NULL; +@@ -100,9 +103,27 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, + if (targetdev == NULL) + return NULL; + +- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); +- if (fcdev == NULL) +- return NULL; ++ rportdev = udev_device_get_parent(targetdev); ++ if (rportdev == NULL) ++ goto skip_npiv_check; ++ ++ hostdev = udev_device_get_parent(rportdev); ++ if (hostdev == NULL) ++ goto skip_npiv_check; ++ ++ vportdev = udev_device_get_parent(hostdev); ++ if (vportdev == NULL) ++ goto skip_npiv_check; ++ ++ fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev)); ++ ++skip_npiv_check: ++ if (fcdev == NULL) { ++ fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); ++ if (fcdev == NULL) ++ return NULL; ++ } ++ + port = udev_device_get_sysattr_value(fcdev, "port_name"); + if (port == NULL) { + parent = NULL; diff --git a/SOURCES/0276-ata_id-unreverse-WWN-identifier.patch b/SOURCES/0276-ata_id-unreverse-WWN-identifier.patch new file mode 100644 index 0000000..afde9b5 --- /dev/null +++ b/SOURCES/0276-ata_id-unreverse-WWN-identifier.patch @@ -0,0 +1,43 @@ +From d1c32b69edc7f0f62a7c3f65691c2cb9fedcb112 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 22 Jul 2015 00:23:47 -0400 +Subject: [PATCH] ata_id: unreverse WWN identifier + +An endianness conversion was lost in 6024a6e302bad6bcf073fa84a41a6123305dc845. +Restore it. Now ata_id and scsi_id output match. + +https://bugzilla.redhat.com/show_bug.cgi?id=1227503 + +Cherry-picked from: 01f61d331bb5038f0c877ac03c54333328b6ea28 +Resolves: #1273306 +--- + src/udev/ata_id/ata_id.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c +index b6f28c6..4adec44 100644 +--- a/src/udev/ata_id/ata_id.c ++++ b/src/udev/ata_id/ata_id.c +@@ -638,10 +638,20 @@ int main(int argc, char *argv[]) + * All other values are reserved. + */ + word = identify.wyde[108]; +- if ((word & 0xf000) == 0x5000) ++ if ((word & 0xf000) == 0x5000) { ++ uint64_t wwwn; ++ ++ wwwn = identify.wyde[108]; ++ wwwn <<= 16; ++ wwwn |= identify.wyde[109]; ++ wwwn <<= 16; ++ wwwn |= identify.wyde[110]; ++ wwwn <<= 16; ++ wwwn |= identify.wyde[111]; + printf("ID_WWN=0x%1$" PRIx64 "\n" + "ID_WWN_WITH_EXTENSION=0x%1$" PRIx64 "\n", +- identify.octa[108/4]); ++ wwwn); ++ } + + /* from Linux's include/linux/ata.h */ + if (identify.wyde[0] == 0x848a || diff --git a/SOURCES/0276-journal-irrelevant-coding-style-fixes.patch b/SOURCES/0276-journal-irrelevant-coding-style-fixes.patch deleted file mode 100644 index 2895df5..0000000 --- a/SOURCES/0276-journal-irrelevant-coding-style-fixes.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 8368db3b100bd587c580d5ed2561390c5ed76a8c Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Sat, 24 Oct 2015 15:08:15 +0200 -Subject: [PATCH] journal: irrelevant coding style fixes - -Cherry-picked from: 0240c603691e006165d8687d6a2c70859755b11f -Related: #1292447 ---- - src/journal/compress.c | 9 +++++---- - src/journal/journal-file.c | 2 +- - 2 files changed, 6 insertions(+), 5 deletions(-) - -diff --git a/src/journal/compress.c b/src/journal/compress.c -index 6923753..c9a3399 100644 ---- a/src/journal/compress.c -+++ b/src/journal/compress.c -@@ -51,10 +51,11 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_ - #ifdef HAVE_XZ - static const lzma_options_lzma opt = { - 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT, -- LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4}; -- static const lzma_filter filters[2] = { -- {LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt}, -- {LZMA_VLI_UNKNOWN, NULL} -+ LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4 -+ }; -+ static const lzma_filter filters[] = { -+ { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt }, -+ { LZMA_VLI_UNKNOWN, NULL } - }; - lzma_ret ret; - size_t out_pos = 0; -diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c -index a8f92e2..892fe47 100644 ---- a/src/journal/journal-file.c -+++ b/src/journal/journal-file.c -@@ -1032,7 +1032,7 @@ static int journal_file_append_data( - r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p); - if (r < 0) - return r; -- else if (r > 0) { -+ if (r > 0) { - - if (ret) - *ret = o; diff --git a/SOURCES/0277-Fixup-WWN-bytes-for-big-endian-systems.patch b/SOURCES/0277-Fixup-WWN-bytes-for-big-endian-systems.patch new file mode 100644 index 0000000..1ed0185 --- /dev/null +++ b/SOURCES/0277-Fixup-WWN-bytes-for-big-endian-systems.patch @@ -0,0 +1,26 @@ +From 2a62c3c66698148f1439176bd6ca5a946b8de550 Mon Sep 17 00:00:00 2001 +From: Tom Lyon +Date: Mon, 21 Sep 2015 14:36:32 -0700 +Subject: [PATCH] Fixup WWN bytes for big-endian systems + +Cherry-picked from: cf22cddcfd07d10fecd7b03ef465e957054daec2 +Resolves: #1273306 +--- + src/udev/ata_id/ata_id.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c +index 4adec44..ef05fba 100644 +--- a/src/udev/ata_id/ata_id.c ++++ b/src/udev/ata_id/ata_id.c +@@ -485,6 +485,10 @@ int main(int argc, char *argv[]) + disk_identify_fixup_uint16(identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */ + disk_identify_fixup_uint16(identify.byte, 91); /* current APM values */ + disk_identify_fixup_uint16(identify.byte, 94); /* current AAM value */ ++ disk_identify_fixup_uint16(identify.byte, 108); /* wwn */ ++ disk_identify_fixup_uint16(identify.byte, 109); /* wwn */ ++ disk_identify_fixup_uint16(identify.byte, 110); /* wwn */ ++ disk_identify_fixup_uint16(identify.byte, 111); /* wwn */ + disk_identify_fixup_uint16(identify.byte, 128); /* device lock function */ + disk_identify_fixup_uint16(identify.byte, 217); /* nominal media rotation rate */ + memcpy(&id, identify.byte, sizeof id); diff --git a/SOURCES/0277-fstab-generator-cescape-device-name-in-root-fsck-ser.patch b/SOURCES/0277-fstab-generator-cescape-device-name-in-root-fsck-ser.patch deleted file mode 100644 index 860308b..0000000 --- a/SOURCES/0277-fstab-generator-cescape-device-name-in-root-fsck-ser.patch +++ /dev/null @@ -1,49 +0,0 @@ -From f29f53f95636fea60a3f757786131790477ab71a Mon Sep 17 00:00:00 2001 -From: Andrei Borzenkov -Date: Wed, 3 Jun 2015 20:50:59 +0300 -Subject: [PATCH] fstab-generator: cescape device name in root-fsck service - -We unescape ExecStart line when parsing it, so escape device name -before adding it to unit file. - -fixes #50 - -Cherry-picked from: fa05e97 -Resolves: #1306126 ---- - src/shared/generator.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/src/shared/generator.c b/src/shared/generator.c -index 3af84a3..be8e24e 100644 ---- a/src/shared/generator.c -+++ b/src/shared/generator.c -@@ -35,8 +35,13 @@ - static int write_fsck_sysroot_service(const char *dir, const char *what) { - const char *unit; - _cleanup_free_ char *device = NULL; -+ _cleanup_free_ char *escaped; - _cleanup_fclose_ FILE *f = NULL; - -+ escaped = cescape(what); -+ if (!escaped) -+ return log_oom(); -+ - unit = strjoina(dir, "/systemd-fsck-root.service"); - log_debug("Creating %s", unit); - -@@ -61,11 +66,12 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { - "[Service]\n" - "Type=oneshot\n" - "RemainAfterExit=yes\n" -- "ExecStart=" SYSTEMD_FSCK_PATH " %2$s\n" -+ "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n" - "TimeoutSec=0\n", - program_invocation_short_name, - what, -- device); -+ device, -+ escaped); - - fflush(f); - if (ferror(f)) diff --git a/SOURCES/0278-manager-reduce-complexity-of-unit_gc_sweep-3507.patch b/SOURCES/0278-manager-reduce-complexity-of-unit_gc_sweep-3507.patch deleted file mode 100644 index 1ecb187..0000000 --- a/SOURCES/0278-manager-reduce-complexity-of-unit_gc_sweep-3507.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 8994877c8c0d2cab6e5c7e8cf98df5ff580d87a8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= -Date: Tue, 14 Jun 2016 14:20:56 +0200 -Subject: [PATCH] manager: reduce complexity of unit_gc_sweep (#3507) - -When unit is marked as UNSURE, we are trying to find if it state was -changed over and over again. So lets not go through the UNSURE states -again. Also when we find a GOOD unit lets propagate the GOOD state to -all units that this unit reference. - -This is a problem on machines with a lot of initscripts with different -starting priority, since those units will reference each other and the -original algorithm might get to n! complexity. - -Thanks HATAYAMA Daisuke for the expand_good_state code. -Cherry-picked from: 4892084f096c19da0e83f28f250ca187b58c22b2 -Resolves: #1344556 ---- - src/core/manager.c | 16 +++++++++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - -diff --git a/src/core/manager.c b/src/core/manager.c -index 7483a96..45ca540 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -765,6 +765,19 @@ enum { - _GC_OFFSET_MAX - }; - -+static void unit_gc_mark_good(Unit *u, unsigned gc_marker) -+{ -+ Iterator i; -+ Unit *other; -+ -+ u->gc_marker = gc_marker + GC_OFFSET_GOOD; -+ -+ /* Recursively mark referenced units as GOOD as well */ -+ SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i) -+ if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE) -+ unit_gc_mark_good(other, gc_marker); -+} -+ - static void unit_gc_sweep(Unit *u, unsigned gc_marker) { - Iterator i; - Unit *other; -@@ -774,6 +787,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) { - - if (u->gc_marker == gc_marker + GC_OFFSET_GOOD || - u->gc_marker == gc_marker + GC_OFFSET_BAD || -+ u->gc_marker == gc_marker + GC_OFFSET_UNSURE || - u->gc_marker == gc_marker + GC_OFFSET_IN_PATH) - return; - -@@ -814,7 +828,7 @@ bad: - return; - - good: -- u->gc_marker = gc_marker + GC_OFFSET_GOOD; -+ unit_gc_mark_good(u, gc_marker); - } - - static unsigned manager_dispatch_gc_queue(Manager *m) { diff --git a/SOURCES/0278-sd-journal-introduce-has_runtime_files-and-has_persi.patch b/SOURCES/0278-sd-journal-introduce-has_runtime_files-and-has_persi.patch new file mode 100644 index 0000000..bd281be --- /dev/null +++ b/SOURCES/0278-sd-journal-introduce-has_runtime_files-and-has_persi.patch @@ -0,0 +1,276 @@ +From 5ec508cc5c13d831c93ce98d84b1d9cedb0117a7 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 1 Feb 2016 09:23:58 +0100 +Subject: [PATCH] sd-journal: introduce has_runtime_files and + has_persistent_files + +Also introduce sd_journal_has_runtime_files() and +sd_journal_has_persistent_files() to the public API. These functions +can be used to easily find out if the open journal files are runtime +and/or persistent. + +Cherry-picked from: 39fd5b08a73f144a20202a665bd25cad51d8a90b +Resolves: #1082179 +--- + Makefile-man.am | 7 +++ + man/sd-journal.xml | 8 ++- + man/sd_journal_has_runtime_files.xml | 95 ++++++++++++++++++++++++++++++++++++ + src/journal/journal-internal.h | 2 + + src/journal/sd-journal.c | 29 +++++++---- + src/systemd/sd-journal.h | 3 ++ + 6 files changed, 133 insertions(+), 11 deletions(-) + create mode 100644 man/sd_journal_has_runtime_files.xml + +diff --git a/Makefile-man.am b/Makefile-man.am +index 497be66..7ec709c 100644 +--- a/Makefile-man.am ++++ b/Makefile-man.am +@@ -40,6 +40,7 @@ MANPAGES += \ + man/sd_journal_get_fd.3 \ + man/sd_journal_get_realtime_usec.3 \ + man/sd_journal_get_usage.3 \ ++ man/sd_journal_has_runtime_files.3 \ + man/sd_journal_next.3 \ + man/sd_journal_open.3 \ + man/sd_journal_print.3 \ +@@ -176,6 +177,7 @@ MANPAGES_ALIAS += \ + man/sd_journal_get_events.3 \ + man/sd_journal_get_monotonic_usec.3 \ + man/sd_journal_get_timeout.3 \ ++ man/sd_journal_has_persistent_files.3 \ + man/sd_journal_next_skip.3 \ + man/sd_journal_open_container.3 \ + man/sd_journal_open_directory.3 \ +@@ -287,6 +289,7 @@ man/sd_journal_get_data_threshold.3: man/sd_journal_get_data.3 + man/sd_journal_get_events.3: man/sd_journal_get_fd.3 + man/sd_journal_get_monotonic_usec.3: man/sd_journal_get_realtime_usec.3 + man/sd_journal_get_timeout.3: man/sd_journal_get_fd.3 ++man/sd_journal_has_persistent_files.3: man/sd_journal_has_runtime_files.3 + man/sd_journal_next_skip.3: man/sd_journal_next.3 + man/sd_journal_open_container.3: man/sd_journal_open.3 + man/sd_journal_open_directory.3: man/sd_journal_open.3 +@@ -500,6 +503,9 @@ man/sd_journal_get_monotonic_usec.html: man/sd_journal_get_realtime_usec.html + man/sd_journal_get_timeout.html: man/sd_journal_get_fd.html + $(html-alias) + ++man/sd_journal_has_persistent_files.html: man/sd_journal_has_runtime_files.html ++ $(html-alias) ++ + man/sd_journal_next_skip.html: man/sd_journal_next.html + $(html-alias) + +@@ -1727,6 +1733,7 @@ EXTRA_DIST += \ + man/sd_journal_get_fd.xml \ + man/sd_journal_get_realtime_usec.xml \ + man/sd_journal_get_usage.xml \ ++ man/sd_journal_has_runtime_files.xml \ + man/sd_journal_next.xml \ + man/sd_journal_open.xml \ + man/sd_journal_print.xml \ +diff --git a/man/sd-journal.xml b/man/sd-journal.xml +index 9b1a522..a1185d3 100644 +--- a/man/sd-journal.xml ++++ b/man/sd-journal.xml +@@ -81,9 +81,11 @@ + sd_journal_get_cutoff_realtime_usec3, + sd_journal_get_cutoff_monotonic_usec3, + sd_journal_get_usage3, +- sd_journal_get_catalog3 ++ sd_journal_get_catalog3, ++ sd_journal_get_fd3, ++ sd_journal_has_runtime_files3 + and +- sd_journal_get_fd3 ++ sd_journal_has_persistent_files3 + for more information about the functions implemented. + + Command line access for submitting entries to the journal is +@@ -116,6 +118,8 @@ + sd_journal_get_fd3, + sd_journal_query_unique3, + sd_journal_get_catalog3, ++ sd_journal_has_runtime_files3, ++ sd_journal_has_persistent_files3, + journalctl1, + sd-id1283, + pkg-config1 +diff --git a/man/sd_journal_has_runtime_files.xml b/man/sd_journal_has_runtime_files.xml +new file mode 100644 +index 0000000..237e649 +--- /dev/null ++++ b/man/sd_journal_has_runtime_files.xml +@@ -0,0 +1,95 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ sd_journal_has_runtime_files ++ systemd ++ ++ ++ ++ Developer ++ Jan ++ Synáček ++ jan.synacek@gmail.com ++ ++ ++ ++ ++ ++ sd_journal_has_runtime_files ++ 3 ++ ++ ++ ++ sd_journal_has_runtime_files ++ sd_journal_has_persistent_files ++ Query availability of runtime or persistent journal files. ++ ++ ++ ++ ++ #include <systemd/sd-journal.h> ++ ++ ++ int sd_journal_has_runtime_files ++ sd_journal *j ++ ++ ++ ++ int sd_journal_has_persistent_files ++ sd_journal *j ++ ++ ++ ++ ++ ++ ++ Description ++ ++ sd_journal_has_runtime_files() returns a positive value ++ if runtime journal files (present in /run/systemd/journal/) have been found. ++ Otherwise returns 0. ++ ++ sd_journal_has_persistent_files() returns a positive value ++ if persistent journal files (present in /var/log/journal/) have been found. ++ Otherwise returns 0. ++ ++ ++ ++ Return value ++ Both sd_journal_has_runtime_files() ++ and sd_journal_has_persistent_files() return -EINVAL ++ if their argument is NULL. ++ ++ ++ ++ ++ See Also ++ ++ sd-journal3 ++ ++ ++ ++ +diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h +index b51ecdb..115d777 100644 +--- a/src/journal/journal-internal.h ++++ b/src/journal/journal-internal.h +@@ -115,6 +115,8 @@ struct sd_journal { + removed, and there were no more + files, so sd_j_enumerate_unique + will return a value equal to 0. */ ++ bool has_runtime_files:1; ++ bool has_persistent_files:1; + + size_t data_threshold; + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 9b9e8ac..20456c3 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -1230,8 +1230,7 @@ static int add_any_file(sd_journal *j, const char *path) { + } + + static int add_file(sd_journal *j, const char *prefix, const char *filename) { +- _cleanup_free_ char *path = NULL; +- int r; ++ char *path = NULL; + + assert(j); + assert(prefix); +@@ -1241,14 +1240,14 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { + !file_type_wanted(j->flags, filename)) + return 0; + +- path = strjoin(prefix, "/", filename, NULL); +- if (!path) +- return -ENOMEM; ++ path = strjoina(prefix, "/", filename); + +- r = add_any_file(j, path); +- if (r == -ENOENT) +- return 0; +- return r; ++ if (!j->has_runtime_files && path_startswith(path, "/run/log/journal")) ++ j->has_runtime_files = true; ++ else if (!j->has_persistent_files && path_startswith(path, "/var/log/journal")) ++ j->has_persistent_files = true; ++ ++ return add_any_file(j, path); + } + + static int remove_file(sd_journal *j, const char *prefix, const char *filename) { +@@ -2616,3 +2615,15 @@ _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) { + *sz = j->data_threshold; + return 0; + } ++ ++_public_ int sd_journal_has_runtime_files(sd_journal *j) { ++ assert_return(j, -EINVAL); ++ ++ return j->has_runtime_files; ++} ++ ++_public_ int sd_journal_has_persistent_files(sd_journal *j) { ++ assert_return(j, -EINVAL); ++ ++ return j->has_persistent_files; ++} +diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h +index 00237a2..d5fd46e 100644 +--- a/src/systemd/sd-journal.h ++++ b/src/systemd/sd-journal.h +@@ -138,6 +138,9 @@ int sd_journal_reliable_fd(sd_journal *j); + int sd_journal_get_catalog(sd_journal *j, char **text); + int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **text); + ++int sd_journal_has_runtime_files(sd_journal *j); ++int sd_journal_has_persistent_files(sd_journal *j); ++ + /* the inverse condition avoids ambiguity of danling 'else' after the macro */ + #define SD_JOURNAL_FOREACH(j) \ + if (sd_journal_seek_head(j) < 0) { } \ diff --git a/SOURCES/0279-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch b/SOURCES/0279-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch deleted file mode 100644 index 7690756..0000000 --- a/SOURCES/0279-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch +++ /dev/null @@ -1,489 +0,0 @@ -From 72696594d40d538e26f6522e064d79f70c8b2f9e Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Wed, 4 May 2016 20:43:23 +0200 -Subject: [PATCH] core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent - notification - -dbus-daemon currently uses a backlog of 30 on its D-bus system bus socket. On -overloaded systems this means that only 30 connections may be queued without -dbus-daemon processing them before further connection attempts fail. Our -cgroups-agent binary so far used D-Bus for its messaging, and hitting this -limit hence may result in us losing cgroup empty messages. - -This patch adds a seperate cgroup agent socket of type AF_UNIX/SOCK_DGRAM. -Since sockets of these types need no connection set up, no listen() backlog -applies. Our cgroup-agent binary will hence simply block as long as it can't -enqueue its datagram message, so that we won't lose cgroup empty messages as -likely anymore. - -This also rearranges the ordering of the processing of SIGCHLD signals, service -notification messages (sd_notify()...) and the two types of cgroup -notifications (inotify for the unified hierarchy support, and agent for the -classic hierarchy support). We now always process events for these in the -following order: - - 1. service notification messages (SD_EVENT_PRIORITY_NORMAL-7) - 2. SIGCHLD signals (SD_EVENT_PRIORITY_NORMAL-6) - 3. cgroup inotify and cgroup agent (SD_EVENT_PRIORITY_NORMAL-5) - -This is because when receiving SIGCHLD we invalidate PID information, which we -need to process the service notification messages which are bound to PIDs. -Hence the order between the first two items. And we want to process SIGCHLD -metadata to detect whether a service is gone, before using cgroup -notifications, to decide when a service is gone, since the former carries more -useful metadata. - -Related to this: -https://bugs.freedesktop.org/show_bug.cgi?id=95264 -https://github.com/systemd/systemd/issues/1961 - -Cherry-picked from: d8fdc62037b5b0a9fd603ad5efd6b49f956f86b5 -Resolves: #1305608 ---- - src/cgroups-agent/cgroups-agent.c | 48 ++++++------ - src/core/cgroup.c | 2 + - src/core/dbus.c | 56 +++++++------- - src/core/dbus.h | 2 + - src/core/manager.c | 149 ++++++++++++++++++++++++++++++++++++-- - src/core/manager.h | 3 + - 6 files changed, 198 insertions(+), 62 deletions(-) - -diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c -index 529e843..2fe6583 100644 ---- a/src/cgroups-agent/cgroups-agent.c -+++ b/src/cgroups-agent/cgroups-agent.c -@@ -1,5 +1,3 @@ --/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ -- - /*** - This file is part of systemd. - -@@ -20,14 +18,21 @@ - ***/ - - #include -+#include - --#include "sd-bus.h" - #include "log.h" --#include "bus-util.h" -+#include "socket-util.h" - - int main(int argc, char *argv[]) { -- _cleanup_bus_close_unref_ sd_bus *bus = NULL; -- int r; -+ -+ static const union sockaddr_union sa = { -+ .un.sun_family = AF_UNIX, -+ .un.sun_path = "/run/systemd/cgroups-agent", -+ }; -+ -+ _cleanup_close_ int fd = -1; -+ ssize_t n; -+ size_t l; - - if (argc != 2) { - log_error("Incorrect number of arguments."); -@@ -38,27 +43,22 @@ int main(int argc, char *argv[]) { - log_parse_environment(); - log_open(); - -- /* We send this event to the private D-Bus socket and then the -- * system instance will forward this to the system bus. We do -- * this to avoid an activation loop when we start dbus when we -- * are called when the dbus service is shut down. */ -- -- r = bus_open_system_systemd(&bus); -- if (r < 0) { -- /* If we couldn't connect we assume this was triggered -- * while systemd got restarted/transitioned from -- * initrd to the system, so let's ignore this */ -- log_debug_errno(r, "Failed to get D-Bus connection: %m"); -+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); -+ if (fd < 0) { -+ log_debug_errno(errno, "Failed to allocate socket: %m"); -+ return EXIT_FAILURE; -+ } -+ -+ l = strlen(argv[1]); -+ -+ n = sendto(fd, argv[1], l, 0, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); -+ if (n < 0) { -+ log_debug_errno(errno, "Failed to send cgroups agent message: %m"); - return EXIT_FAILURE; - } - -- r = sd_bus_emit_signal(bus, -- "/org/freedesktop/systemd1/agent", -- "org.freedesktop.systemd1.Agent", -- "Released", -- "s", argv[1]); -- if (r < 0) { -- log_debug_errno(r, "Failed to send signal message on private connection: %m"); -+ if ((size_t) n != l) { -+ log_debug("Datagram size mismatch"); - return EXIT_FAILURE; - } - -diff --git a/src/core/cgroup.c b/src/core/cgroup.c -index 10fdcc9..b7f08fb 100644 ---- a/src/core/cgroup.c -+++ b/src/core/cgroup.c -@@ -1028,6 +1028,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) { - assert(m); - assert(cgroup); - -+ log_debug("Got cgroup empty notification for: %s", cgroup); -+ - u = manager_get_unit_by_cgroup(m, cgroup); - if (u) { - r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true); -diff --git a/src/core/dbus.c b/src/core/dbus.c -index 85b5174..29524d4 100644 ---- a/src/core/dbus.c -+++ b/src/core/dbus.c -@@ -72,12 +72,37 @@ int bus_send_queued_message(Manager *m) { - return 0; - } - -+int bus_forward_agent_released(Manager *m, const char *path) { -+ int r; -+ -+ assert(m); -+ assert(path); -+ -+ if (!m->running_as == SYSTEMD_SYSTEM) -+ return 0; -+ -+ if (!m->system_bus) -+ return 0; -+ -+ /* If we are running a system instance we forward the agent message on the system bus, so that the user -+ * instances get notified about this, too */ -+ -+ r = sd_bus_emit_signal(m->system_bus, -+ "/org/freedesktop/systemd1/agent", -+ "org.freedesktop.systemd1.Agent", -+ "Released", -+ "s", path); -+ if (r < 0) -+ return log_warning_errno(r, "Failed to propagate agent release message: %m"); -+ -+ return 1; -+} -+ - static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { - Manager *m = userdata; - const char *cgroup; - int r; - -- assert(bus); - assert(message); - assert(m); - -@@ -88,16 +113,6 @@ static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *use - } - - manager_notify_cgroup_empty(m, cgroup); -- -- if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) { -- /* If we are running as system manager, forward the -- * message to the system bus */ -- -- r = sd_bus_send(m->system_bus, message, NULL); -- if (r < 0) -- log_warning_errno(r, "Failed to forward Released message: %m"); -- } -- - return 0; - } - -@@ -679,25 +694,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void - return 0; - } - -- if (m->running_as == SYSTEMD_SYSTEM) { -- /* When we run as system instance we get the Released -- * signal via a direct connection */ -- -- r = sd_bus_add_match( -- bus, -- NULL, -- "type='signal'," -- "interface='org.freedesktop.systemd1.Agent'," -- "member='Released'," -- "path='/org/freedesktop/systemd1/agent'", -- signal_agent_released, m); -- -- if (r < 0) { -- log_warning_errno(r, "Failed to register Released match on new connection bus: %m"); -- return 0; -- } -- } -- - r = bus_setup_disconnected_match(m, bus); - if (r < 0) - return 0; -diff --git a/src/core/dbus.h b/src/core/dbus.h -index d04f532..c27d136 100644 ---- a/src/core/dbus.h -+++ b/src/core/dbus.h -@@ -40,3 +40,5 @@ int bus_verify_manage_unit_async(Manager *m, sd_bus_message *call, sd_bus_error - int bus_verify_manage_unit_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error); - int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error); - int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error); -+ -+int bus_forward_agent_released(Manager *m, const char *path); -diff --git a/src/core/manager.c b/src/core/manager.c -index 45ca540..b6d76ca 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -83,8 +83,10 @@ - #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC) - #define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3) - #define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3 -+#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024) - - static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); -+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); - static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); - static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); - static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); -@@ -456,11 +458,11 @@ static int manager_setup_signals(Manager *m) { - if (r < 0) - return r; - -- /* Process signals a bit earlier than the rest of things, but -- * later than notify_fd processing, so that the notify -- * processing can still figure out to which process/service a -- * message belongs, before we reap the process. */ -- r = sd_event_source_set_priority(m->signal_event_source, -5); -+ /* Process signals a bit earlier than the rest of things, but later than notify_fd processing, so that the -+ * notify processing can still figure out to which process/service a message belongs, before we reap the -+ * process. Also, process this before handling cgroup notifications, so that we always collect child exit -+ * status information before detecting that there's no process in a cgroup. */ -+ r = sd_event_source_set_priority(m->signal_event_source, -6); - if (r < 0) - return r; - -@@ -541,7 +543,7 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) { - - m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; - -- m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1; -+ m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1; - m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ - - m->ask_password_inotify_fd = -1; -@@ -689,8 +691,8 @@ static int manager_setup_notify(Manager *m) { - if (r < 0) - return log_error_errno(r, "Failed to allocate notify event source: %m"); - -- /* Process signals a bit earlier than SIGCHLD, so that we can -- * still identify to which service an exit message belongs */ -+ /* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which -+ * service an exit message belongs. */ - r = sd_event_source_set_priority(m->notify_event_source, -7); - if (r < 0) - return log_error_errno(r, "Failed to set priority of notify event source: %m"); -@@ -699,6 +701,77 @@ static int manager_setup_notify(Manager *m) { - return 0; - } - -+static int manager_setup_cgroups_agent(Manager *m) { -+ -+ static const union sockaddr_union sa = { -+ .un.sun_family = AF_UNIX, -+ .un.sun_path = "/run/systemd/cgroups-agent", -+ }; -+ int r; -+ -+ /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering -+ * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and -+ * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on -+ * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number -+ * of D-Bus connections may be queued until the kernel will start dropping further incoming connections, -+ * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX -+ * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and -+ * we thus won't lose messages. -+ * -+ * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen -+ * to it. The system instance hence listens on this special socket, but the user instances listen on the system -+ * bus for these messages. */ -+ -+ if (m->test_run) -+ return 0; -+ -+ if (!m->running_as == SYSTEMD_SYSTEM) -+ return 0; -+ -+ if (m->cgroups_agent_fd < 0) { -+ _cleanup_close_ int fd = -1; -+ -+ /* First free all secondary fields */ -+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source); -+ -+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); -+ if (fd < 0) -+ return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m"); -+ -+ fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE); -+ -+ (void) unlink(sa.un.sun_path); -+ -+ /* Only allow root to connect to this socket */ -+ RUN_WITH_UMASK(0077) -+ r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); -+ if (r < 0) -+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); -+ -+ m->cgroups_agent_fd = fd; -+ fd = -1; -+ } -+ -+ if (!m->cgroups_agent_event_source) { -+ r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m); -+ if (r < 0) -+ return log_error_errno(r, "Failed to allocate cgroups agent event source: %m"); -+ -+ /* Process cgroups notifications early, but after having processed service notification messages or -+ * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification, -+ * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of -+ * cgroup inotify for the unified cgroup stuff. */ -+ r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5); -+ if (r < 0) -+ return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m"); -+ -+ (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent"); -+ } -+ -+ return 0; -+} -+ -+ - static int manager_setup_kdbus(Manager *m) { - #ifdef ENABLE_KDBUS - _cleanup_free_ char *p = NULL; -@@ -926,6 +999,7 @@ Manager* manager_free(Manager *m) { - - sd_event_source_unref(m->signal_event_source); - sd_event_source_unref(m->notify_event_source); -+ sd_event_source_unref(m->cgroups_agent_event_source); - sd_event_source_unref(m->time_change_event_source); - sd_event_source_unref(m->jobs_in_progress_event_source); - sd_event_source_unref(m->idle_pipe_event_source); -@@ -933,6 +1007,7 @@ Manager* manager_free(Manager *m) { - - safe_close(m->signal_fd); - safe_close(m->notify_fd); -+ safe_close(m->cgroups_agent_fd); - safe_close(m->time_change_fd); - safe_close(m->kdbus_fd); - -@@ -1181,6 +1256,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { - if (q < 0 && r == 0) - r = q; - -+ q = manager_setup_cgroups_agent(m); -+ if (q < 0 && r == 0) -+ r = q; -+ - /* We might have deserialized the kdbus control fd, but if we - * didn't, then let's create the bus now. */ - manager_setup_kdbus(m); -@@ -1502,6 +1581,35 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { - return n; - } - -+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { -+ Manager *m = userdata; -+ char buf[PATH_MAX+1]; -+ ssize_t n; -+ -+ n = recv(fd, buf, sizeof(buf), 0); -+ if (n < 0) -+ return log_error_errno(errno, "Failed to read cgroups agent message: %m"); -+ if (n == 0) { -+ log_error("Got zero-length cgroups agent message, ignoring."); -+ return 0; -+ } -+ if ((size_t) n >= sizeof(buf)) { -+ log_error("Got overly long cgroups agent message, ignoring."); -+ return 0; -+ } -+ -+ if (memchr(buf, 0, n)) { -+ log_error("Got cgroups agent message with embedded NUL byte, ignoring."); -+ return 0; -+ } -+ buf[n] = 0; -+ -+ manager_notify_cgroup_empty(m, buf); -+ bus_forward_agent_released(m, buf); -+ -+ return 0; -+} -+ - static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) { - _cleanup_strv_free_ char **tags = NULL; - -@@ -2314,6 +2422,16 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { - fprintf(f, "notify-socket=%s\n", m->notify_socket); - } - -+ if (m->cgroups_agent_fd >= 0) { -+ int copy; -+ -+ copy = fdset_put_dup(fds, m->cgroups_agent_fd); -+ if (copy < 0) -+ return copy; -+ -+ fprintf(f, "cgroups-agent-fd=%i\n", copy); -+ } -+ - if (m->kdbus_fd >= 0) { - int copy; - -@@ -2483,6 +2601,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { - free(m->notify_socket); - m->notify_socket = n; - -+ } else if (startswith(l, "cgroups-agent-fd=")) { -+ int fd; -+ -+ if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) -+ log_debug("Failed to parse cgroups agent fd: %s", l + 10); -+ else { -+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source); -+ safe_close(m->cgroups_agent_fd); -+ m->cgroups_agent_fd = fdset_remove(fds, fd); -+ } -+ - } else if (startswith(l, "kdbus-fd=")) { - int fd; - -@@ -2609,6 +2738,10 @@ int manager_reload(Manager *m) { - if (q < 0 && r >= 0) - r = q; - -+ q = manager_setup_cgroups_agent(m); -+ if (q < 0 && r >= 0) -+ r = q; -+ - /* Third, fire things up! */ - q = manager_coldplug(m); - if (q < 0 && r >= 0) -diff --git a/src/core/manager.h b/src/core/manager.h -index d3971f1..3e855db 100644 ---- a/src/core/manager.h -+++ b/src/core/manager.h -@@ -137,6 +137,9 @@ struct Manager { - int notify_fd; - sd_event_source *notify_event_source; - -+ int cgroups_agent_fd; -+ sd_event_source *cgroups_agent_event_source; -+ - int signal_fd; - sd_event_source *signal_event_source; - diff --git a/SOURCES/0279-journalctl-improve-error-messages-when-the-specified.patch b/SOURCES/0279-journalctl-improve-error-messages-when-the-specified.patch new file mode 100644 index 0000000..d79bc02 --- /dev/null +++ b/SOURCES/0279-journalctl-improve-error-messages-when-the-specified.patch @@ -0,0 +1,31 @@ +From 046d996001c0b3fe34d34683e55f62481a5af932 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 1 Feb 2016 09:29:02 +0100 +Subject: [PATCH] journalctl: improve error messages when the specified boot is + not found + +Cherry-picked from: c34e939909710bf124e7741c3648592a30418ffd +Resolves: #1082179 +--- + src/journal/journalctl.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 7058788..964f849 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1090,10 +1090,11 @@ static int add_boot(sd_journal *j) { + const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r); + + if (sd_id128_is_null(arg_boot_id)) +- log_error("Failed to look up boot %+i: %s", arg_boot_offset, reason); ++ log_error("Data from the specified boot (%+i) is not available: %s", ++ arg_boot_offset, reason); + else +- log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s", +- SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, reason); ++ log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s", ++ SD_ID128_FORMAT_VAL(arg_boot_id), reason); + + return r == 0 ? -ENODATA : r; + } diff --git a/SOURCES/0280-journalctl-show-friendly-info-when-using-b-on-runtim.patch b/SOURCES/0280-journalctl-show-friendly-info-when-using-b-on-runtim.patch new file mode 100644 index 0000000..1938244 --- /dev/null +++ b/SOURCES/0280-journalctl-show-friendly-info-when-using-b-on-runtim.patch @@ -0,0 +1,33 @@ +From a932c70a76846aa7dbb4b783291b44bfc8cbd76c Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 1 Feb 2016 09:25:22 +0100 +Subject: [PATCH] journalctl: show friendly info when using -b on runtime + journal only + +Make it clear that specifing boot when there is actually only one has no +effect. This cosmetic patch improves user experience a bit. + +Cherry-picked from: 0f1a9a830c87d8accdc3a44d0a93ad343e52a7bd +Resolves: #1082179 +--- + src/journal/journalctl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 964f849..836d7d2 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1905,6 +1905,13 @@ int main(int argc, char *argv[]) { + goto finish; + } + ++ if (arg_boot_offset != 0 && ++ sd_journal_has_runtime_files(j) > 0 && ++ sd_journal_has_persistent_files(j) == 0) { ++ log_info("Specifying boot ID has no effect, no persistent journal was found"); ++ r = 0; ++ goto finish; ++ } + /* add_boot() must be called first! + * It may need to seek the journal to find parent boot IDs. */ + r = add_boot(j); diff --git a/SOURCES/0280-logind-process-session-inhibitor-fds-at-higher-prior.patch b/SOURCES/0280-logind-process-session-inhibitor-fds-at-higher-prior.patch deleted file mode 100644 index a396534..0000000 --- a/SOURCES/0280-logind-process-session-inhibitor-fds-at-higher-prior.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 5eeac990b887d7cbe8a4b234918f19f64a57079a Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Wed, 4 May 2016 19:01:56 +0200 -Subject: [PATCH] logind: process session/inhibitor fds at higher priority - -Let's make sure we process session and inhibitor pipe fds (that signal -sessions/inhibtors going away) at a higher priority -than new bus calls that might create new sessions or inhibitors. This helps -ensuring that the number of open sessions stays minimal. - -Cherry-picked from: e11544a8305ab9dea097c74bb16e296150c9cc10 -Resolves: #1305608 ---- - src/login/logind-inhibit.c | 2 +- - src/login/logind-session.c | 4 +++- - src/login/logind.c | 2 +- - 3 files changed, 5 insertions(+), 3 deletions(-) - -diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c -index 84fee0e..bf96898 100644 ---- a/src/login/logind-inhibit.c -+++ b/src/login/logind-inhibit.c -@@ -303,7 +303,7 @@ int inhibitor_create_fifo(Inhibitor *i) { - if (r < 0) - return r; - -- r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE); -+ r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10); - if (r < 0) - return r; - } -diff --git a/src/login/logind-session.c b/src/login/logind-session.c -index d2e7b40..f39eb78 100644 ---- a/src/login/logind-session.c -+++ b/src/login/logind-session.c -@@ -888,7 +888,9 @@ int session_create_fifo(Session *s) { - if (r < 0) - return r; - -- r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE); -+ /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new -+ * sessions). */ -+ r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10); - if (r < 0) - return r; - } -diff --git a/src/login/logind.c b/src/login/logind.c -index 3afbf34..e8d0669 100644 ---- a/src/login/logind.c -+++ b/src/login/logind.c -@@ -685,7 +685,7 @@ static int manager_connect_bus(Manager *m) { - if (r < 0) - return log_error_errno(r, "Failed to register name: %m"); - -- r = sd_bus_attach_event(m->bus, m->event, 0); -+ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL); - if (r < 0) - return log_error_errno(r, "Failed to attach bus to event loop: %m"); - diff --git a/SOURCES/0281-journalctl-make-journalctl-dev-sda-work.patch b/SOURCES/0281-journalctl-make-journalctl-dev-sda-work.patch new file mode 100644 index 0000000..5ce2fbb --- /dev/null +++ b/SOURCES/0281-journalctl-make-journalctl-dev-sda-work.patch @@ -0,0 +1,206 @@ +From 1c33de9e1370bc56e10f3b5306e27c8aa6a18873 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 1 Feb 2016 10:44:58 +0100 +Subject: [PATCH] journalctl: make "journalctl /dev/sda" work + +Currently when journalctl is called with path to block device node we +add following match _KERNEL_DEVICE=b$MAJOR:$MINOR. + +That is not sufficient to actually obtain logs about the disk because +dev_printk() kernel helper puts to /dev/kmsg information about the +device in following format, +$SUBSYSTEM:$ADDRESS, +e.g. "+pci:pci:0000:00:14.0". + +Now we will walk upward the syspath and add match for every device in +format produced by dev_printk() as well as match for its device node if +it exists. + +Cherry-picked from: 795ab08f783e78e85f1493879f13ac44cb113b00 +Resolves: #947636 +--- + Makefile.am | 3 +- + src/journal/journalctl.c | 118 ++++++++++++++++++++++++++++++++++++++--------- + 2 files changed, 97 insertions(+), 24 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 2645f66..2559376 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4245,7 +4245,8 @@ journalctl_LDADD = \ + libsystemd-journal-internal.la \ + libsystemd-internal.la \ + libsystemd-logs.la \ +- libsystemd-shared.la ++ libsystemd-shared.la \ ++ libudev-core.la + + if HAVE_ACL + journalctl_LDADD += \ +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 836d7d2..3db1cd2 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -63,6 +63,8 @@ + #include "mkdir.h" + #include "bus-util.h" + #include "bus-error.h" ++#include "udev.h" ++#include "udev-util.h" + + #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) + +@@ -134,6 +136,80 @@ typedef struct boot_id_t { + LIST_FIELDS(struct boot_id_t, boot_list); + } boot_id_t; + ++static int add_matches_for_device(sd_journal *j, const char *devpath) { ++ int r; ++ _cleanup_udev_unref_ struct udev *udev = NULL; ++ _cleanup_udev_device_unref_ struct udev_device *device = NULL; ++ struct udev_device *d = NULL; ++ struct stat st; ++ ++ assert(j); ++ assert(devpath); ++ ++ if (!path_startswith(devpath, "/dev/")) { ++ log_error("Devpath does not start with /dev/"); ++ return -EINVAL; ++ } ++ ++ udev = udev_new(); ++ if (!udev) ++ return log_oom(); ++ ++ r = stat(devpath, &st); ++ if (r < 0) ++ log_error_errno(errno, "Couldn't stat file: %m"); ++ ++ d = device = udev_device_new_from_devnum(udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev); ++ if (!device) ++ return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev)); ++ ++ while (d) { ++ _cleanup_free_ char *match = NULL; ++ const char *subsys, *sysname, *devnode; ++ ++ subsys = udev_device_get_subsystem(d); ++ if (!subsys) { ++ d = udev_device_get_parent(d); ++ continue; ++ } ++ ++ sysname = udev_device_get_sysname(d); ++ if (!sysname) { ++ d = udev_device_get_parent(d); ++ continue; ++ } ++ ++ match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname, NULL); ++ if (!match) ++ return log_oom(); ++ ++ r = sd_journal_add_match(j, match, 0); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add match: %m"); ++ ++ devnode = udev_device_get_devnode(d); ++ if (devnode) { ++ _cleanup_free_ char *match1 = NULL; ++ ++ r = stat(devnode, &st); ++ if (r < 0) ++ return log_error_errno(r, "Failed to stat() device node \"%s\": %m", devnode); ++ ++ r = asprintf(&match1, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st.st_mode) ? 'b' : 'c', major(st.st_rdev), minor(st.st_rdev)); ++ if (r < 0) ++ return log_oom(); ++ ++ r = sd_journal_add_match(j, match1, 0); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add match: %m"); ++ } ++ ++ d = udev_device_get_parent(d); ++ } ++ ++ return 0; ++} ++ + static void pager_open_if_enabled(void) { + + if (arg_no_pager) +@@ -788,13 +864,12 @@ static int add_matches(sd_journal *j, char **args) { + have_term = false; + + } else if (path_is_absolute(*i)) { +- _cleanup_free_ char *p, *t = NULL, *t2 = NULL; ++ _cleanup_free_ char *p, *t = NULL, *t2 = NULL, *interpreter = NULL; + const char *path; +- _cleanup_free_ char *interpreter = NULL; + struct stat st; + + p = canonicalize_file_name(*i); +- path = p ? p : *i; ++ path = p ?: *i; + + if (stat(path, &st) < 0) + return log_error_errno(errno, "Couldn't stat file: %m"); +@@ -808,40 +883,37 @@ static int add_matches(sd_journal *j, char **args) { + return log_oom(); + + t = strappend("_COMM=", comm); ++ if (!t) ++ return log_oom(); + + /* Append _EXE only if the interpreter is not a link. + Otherwise, it might be outdated often. */ +- if (lstat(interpreter, &st) == 0 && +- !S_ISLNK(st.st_mode)) { ++ if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)) { + t2 = strappend("_EXE=", interpreter); + if (!t2) + return log_oom(); + } +- } else ++ } else { + t = strappend("_EXE=", path); +- } else if (S_ISCHR(st.st_mode)) { +- if (asprintf(&t, "_KERNEL_DEVICE=c%u:%u", +- major(st.st_rdev), +- minor(st.st_rdev)) < 0) +- return -ENOMEM; +- } else if (S_ISBLK(st.st_mode)) { +- if (asprintf(&t, "_KERNEL_DEVICE=b%u:%u", +- major(st.st_rdev), +- minor(st.st_rdev)) < 0) +- return -ENOMEM; ++ if (!t) ++ return log_oom(); ++ } ++ ++ r = sd_journal_add_match(j, t, 0); ++ ++ if (r >=0 && t2) ++ r = sd_journal_add_match(j, t2, 0); ++ ++ } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { ++ r = add_matches_for_device(j, path); ++ if (r < 0) ++ return r; + } else { + log_error("File is neither a device node, nor regular file, nor executable: %s", *i); + return -EINVAL; + } + +- if (!t) +- return log_oom(); +- +- r = sd_journal_add_match(j, t, 0); +- if (t2) +- r = sd_journal_add_match(j, t2, 0); + have_term = true; +- + } else { + r = sd_journal_add_match(j, *i, 0); + have_term = true; diff --git a/SOURCES/0281-sd-event-expose-the-event-loop-iteration-counter-via.patch b/SOURCES/0281-sd-event-expose-the-event-loop-iteration-counter-via.patch deleted file mode 100644 index 98ff349..0000000 --- a/SOURCES/0281-sd-event-expose-the-event-loop-iteration-counter-via.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 782a6f41f36317fe837f8c85d2fc7b9b5de98200 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Wed, 29 Jun 2016 19:03:26 -0700 -Subject: [PATCH] sd-event: expose the event loop iteration counter via - sd_event_get_iteration() - -This extends the existing event loop iteration counter to 64bit, and exposes it -via a new function sd_event_get_iteration(). This is helpful for cases like -issue #3612. After all, since we maintain the counter anyway, we might as well -expose it. - -(This also fixes an unrelated issue in the man page for sd_event_wait() where -micro and milliseconds got mixed up) - -Cherry-picked from: 7486322b99da5b4d2d00d35b310b035f936f7964 -Related: #1342173 ---- - src/libsystemd/sd-event/sd-event.c | 14 +++++++++++--- - src/systemd/sd-event.h | 1 + - 2 files changed, 12 insertions(+), 3 deletions(-) - -diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c -index 1f1e6fe..9d48e5a 100644 ---- a/src/libsystemd/sd-event/sd-event.c -+++ b/src/libsystemd/sd-event/sd-event.c -@@ -76,8 +76,8 @@ struct sd_event_source { - int64_t priority; - unsigned pending_index; - unsigned prepare_index; -- unsigned pending_iteration; -- unsigned prepare_iteration; -+ uint64_t pending_iteration; -+ uint64_t prepare_iteration; - - LIST_FIELDS(sd_event_source, sources); - -@@ -169,7 +169,7 @@ struct sd_event { - - pid_t original_pid; - -- unsigned iteration; -+ uint64_t iteration; - dual_timestamp timestamp; - usec_t timestamp_boottime; - int state; -@@ -2689,3 +2689,11 @@ _public_ int sd_event_get_watchdog(sd_event *e) { - - return e->watchdog; - } -+ -+_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { -+ assert_return(e, -EINVAL); -+ assert_return(!event_pid_changed(e), -ECHILD); -+ -+ *ret = e->iteration; -+ return 0; -+} -diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h -index 25a10f9..4957f3a 100644 ---- a/src/systemd/sd-event.h -+++ b/src/systemd/sd-event.h -@@ -101,6 +101,7 @@ int sd_event_get_tid(sd_event *e, pid_t *tid); - int sd_event_get_exit_code(sd_event *e, int *code); - int sd_event_set_watchdog(sd_event *e, int b); - int sd_event_get_watchdog(sd_event *e); -+int sd_event_get_iteration(sd_event *e, uint64_t *ret); - - sd_event_source* sd_event_source_ref(sd_event_source *s); - sd_event_source* sd_event_source_unref(sd_event_source *s); diff --git a/SOURCES/0282-journalctl-add-match-for-the-current-boot-when-calle.patch b/SOURCES/0282-journalctl-add-match-for-the-current-boot-when-calle.patch new file mode 100644 index 0000000..60736b2 --- /dev/null +++ b/SOURCES/0282-journalctl-add-match-for-the-current-boot-when-calle.patch @@ -0,0 +1,27 @@ +From fb7acf90df3d675261b18f8e7c2de315dadee756 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 3 Feb 2016 11:22:52 +0100 +Subject: [PATCH] journalctl: add match for the current boot when called with + devpath + +Cherry-picked from: 485fd9a7b9d59b9f2302a873f7ee5ccac256dd93 +Related: #947636 +--- + src/journal/journalctl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 3db1cd2..6948ed6 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -207,6 +207,10 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) { + d = udev_device_get_parent(d); + } + ++ r = add_match_this_boot(j, arg_machine); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add match for the current boot: %m"); ++ + return 0; + } + diff --git a/SOURCES/0282-manager-Only-invoke-a-single-sigchld-per-unit-within.patch b/SOURCES/0282-manager-Only-invoke-a-single-sigchld-per-unit-within.patch deleted file mode 100644 index ba20e3a..0000000 --- a/SOURCES/0282-manager-Only-invoke-a-single-sigchld-per-unit-within.patch +++ /dev/null @@ -1,85 +0,0 @@ -From f84b01e4d13d155bd0a8a429c5d18e855414de4b Mon Sep 17 00:00:00 2001 -From: Kyle Walker -Date: Thu, 30 Jun 2016 15:12:18 -0400 -Subject: [PATCH] manager: Only invoke a single sigchld per unit within a - cleanup cycle - -By default, each iteration of manager_dispatch_sigchld() results in a unit level -sigchld event being invoked. For scope units, this results in a scope_sigchld_event() -which can seemingly stall for workloads that have a large number of PIDs within the -scope. The stall exhibits itself as a SIG_0 being initiated for each u->pids entry -as a result of pid_is_unwaited(). - -v2: -This patch resolves this condition by only paying to cost of a sigchld in the underlying -scope unit once per sigchld iteration. A new "sigchldgen" member resides within the -Unit struct. The Manager is incremented via the sd event loop, accessed via -sd_event_get_iteration, and the Unit member is set to the same value as the manager each -time that a sigchld event is invoked. If the Manager iteration value and Unit member -match, the sigchld event is not invoked for that iteration. - -Cherry-picked from: 36f20ae3b2975e44b6ef17e453ae06a289e9a122 -Resolves: #1342173 ---- - src/core/manager.c | 13 ++++++++++++- - src/core/unit.c | 1 + - src/core/unit.h | 3 +++ - 3 files changed, 16 insertions(+), 1 deletion(-) - -diff --git a/src/core/manager.c b/src/core/manager.c -index b6d76ca..f2f5c6a 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -1743,14 +1743,25 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t - } - - static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { -+ uint64_t iteration; -+ - assert(m); - assert(u); - assert(si); - -+ sd_event_get_iteration(m->event, &iteration); -+ - log_unit_debug(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id); - - unit_unwatch_pid(u, si->si_pid); -- UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); -+ -+ if (UNIT_VTABLE(u)->sigchld_event) { -+ if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { -+ UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); -+ u->sigchldgen = iteration; -+ } else -+ log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); -+ } - } - - static int manager_dispatch_sigchld(Manager *m) { -diff --git a/src/core/unit.c b/src/core/unit.c -index 4fb2fd3..5b2becc 100644 ---- a/src/core/unit.c -+++ b/src/core/unit.c -@@ -94,6 +94,7 @@ Unit *unit_new(Manager *m, size_t size) { - u->unit_file_state = _UNIT_FILE_STATE_INVALID; - u->unit_file_preset = -1; - u->on_failure_job_mode = JOB_REPLACE; -+ u->sigchldgen = 0; - - return u; - } -diff --git a/src/core/unit.h b/src/core/unit.h -index 0eebc0b..d936457 100644 ---- a/src/core/unit.h -+++ b/src/core/unit.h -@@ -167,6 +167,9 @@ struct Unit { - * process SIGCHLD for */ - Set *pids; - -+ /* Used in sigchld event invocation to avoid repeat events being invoked */ -+ uint64_t sigchldgen; -+ - /* Used during GC sweeps */ - unsigned gc_marker; - diff --git a/SOURCES/0283-man-clarify-what-happens-when-journalctl-is-called-w.patch b/SOURCES/0283-man-clarify-what-happens-when-journalctl-is-called-w.patch new file mode 100644 index 0000000..7678f12 --- /dev/null +++ b/SOURCES/0283-man-clarify-what-happens-when-journalctl-is-called-w.patch @@ -0,0 +1,33 @@ +From a4f12d4849daed23651ab3c23b5ff830aa32b2a0 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 3 Feb 2016 10:38:29 +0100 +Subject: [PATCH] man: clarify what happens when journalctl is called with + devpath + +Cherry-picked from: 3cea8e06e45fc1757de8f74da29fb5fb181db4eb +Related: #947636 +--- + man/journalctl.xml | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index 2764f66..0981fba 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -91,8 +91,14 @@ + paths may be specified. If a file path refers to an executable + file, this is equivalent to an _EXE= match + for the canonicalized binary path. Similarly, if a path refers +- to a device node, this is equivalent to a +- _KERNEL_DEVICE= match for the device. ++ to a device node then match is added for the kernel name of the ++ device (_KERNEL_DEVICE=). Also, matches for the ++ kernel names of all the parent devices are added automatically. ++ Device node paths are not stable across reboots, therefore match ++ for the current boot id (_BOOT_ID=) is ++ always added as well. Note that only the log entries for ++ the existing device nodes maybe queried by providing path to ++ the device node. + + Additional constraints may be added using options + , , etc, to diff --git a/SOURCES/0283-manager-Fixing-a-debug-printf-formatting-mistake.patch b/SOURCES/0283-manager-Fixing-a-debug-printf-formatting-mistake.patch deleted file mode 100644 index 007e1ab..0000000 --- a/SOURCES/0283-manager-Fixing-a-debug-printf-formatting-mistake.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 69ecc270c614acdb5469551ac3dbe41bd43c44ae Mon Sep 17 00:00:00 2001 -From: Kyle Walker -Date: Fri, 1 Jul 2016 10:04:40 -0400 -Subject: [PATCH] manager: Fixing a debug printf formatting mistake - -A 'llu' formatting statement was used in a debugging printf statement -instead of a 'PRIu64'. Correcting that mistake here. - -Cherry-picked from: 72b0c3f59695239c51b719576f625e789bd00a66 -Related: #1342173 ---- - src/core/manager.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/core/manager.c b/src/core/manager.c -index f2f5c6a..b63d929 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -1760,7 +1760,8 @@ static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { - UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); - u->sigchldgen = iteration; - } else -- log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); -+ log_debug("%s already issued a sigchld this iteration %" PRIu64 ", skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); -+ - } - } - diff --git a/SOURCES/0284-core-downgrade-warning-about-duplicate-device-names.patch b/SOURCES/0284-core-downgrade-warning-about-duplicate-device-names.patch new file mode 100644 index 0000000..70a46a9 --- /dev/null +++ b/SOURCES/0284-core-downgrade-warning-about-duplicate-device-names.patch @@ -0,0 +1,26 @@ +From ad2cedec3cf3e6ddefd70d9f3dece3ca837676cf Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 23 Apr 2015 13:50:01 +0200 +Subject: [PATCH] core: downgrade warning about duplicate device names + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/031094.html + +Cherry-picked from: 5259bcf6a638d8d489db1ddefd55327aa15f3e51 +Resolves: #1296249 +--- + src/core/device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/device.c b/src/core/device.c +index 8a6855d..1995e3c 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -317,7 +317,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa + if (u && + DEVICE(u)->sysfs && + !path_equal(DEVICE(u)->sysfs, sysfs)) { +- log_unit_error(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); ++ log_unit_debug(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); + return -EEXIST; + } + diff --git a/SOURCES/0284-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch b/SOURCES/0284-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch deleted file mode 100644 index d4bc7c1..0000000 --- a/SOURCES/0284-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch +++ /dev/null @@ -1,248 +0,0 @@ -From 35bf3bd6a276fa58fa6ed5a258a7fbc4ba8bce05 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= -Date: Sat, 16 Jul 2016 21:04:13 +0200 -Subject: [PATCH] manager: don't skip sigchld handler for main and control pid - for services (#3738) - -During stop when service has one "regular" pid one main pid and one -control pid and the sighld for the regular one is processed first the -unit_tidy_watch_pids will skip the main and control pid and does not -remove them from u->pids(). But then we skip the sigchld event because we -already did one in the iteration and there are two pids in u->pids. - -v2: Use general unit_main_pid() and unit_control_pid() instead of -reaching directly to service structure. -Cherry-picked from: ccc2c98e1b0c06861577632440b996ca16cefd53 -Resolves: #1342173 ---- - src/core/busname.c | 10 ++++++++++ - src/core/manager.c | 5 ++++- - src/core/mount.c | 10 ++++++++++ - src/core/service.c | 19 +++++++++++++++++++ - src/core/socket.c | 10 ++++++++++ - src/core/swap.c | 10 ++++++++++ - src/core/unit.c | 18 ++++++++++++++++++ - src/core/unit.h | 9 +++++++++ - 8 files changed, 90 insertions(+), 1 deletion(-) - -diff --git a/src/core/busname.c b/src/core/busname.c -index 43d7607..f626ba9 100644 ---- a/src/core/busname.c -+++ b/src/core/busname.c -@@ -997,6 +997,14 @@ static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { - - DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); - -+static int busname_control_pid(Unit *u) { -+ BusName *n = BUSNAME(u); -+ -+ assert(n); -+ -+ return n->control_pid; -+} -+ - static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { - [BUSNAME_SUCCESS] = "success", - [BUSNAME_FAILURE_RESOURCES] = "resources", -@@ -1047,6 +1055,8 @@ const UnitVTable busname_vtable = { - - .supported = busname_supported, - -+ .control_pid = busname_control_pid, -+ - .bus_interface = "org.freedesktop.systemd1.BusName", - .bus_vtable = bus_busname_vtable, - -diff --git a/src/core/manager.c b/src/core/manager.c -index b63d929..87b5e57 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -1756,7 +1756,10 @@ static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { - unit_unwatch_pid(u, si->si_pid); - - if (UNIT_VTABLE(u)->sigchld_event) { -- if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { -+ if (set_size(u->pids) <= 1 || -+ iteration != u->sigchldgen || -+ unit_main_pid(u) == si->si_pid || -+ unit_control_pid(u) == si->si_pid) { - UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); - u->sigchldgen = iteration; - } else -diff --git a/src/core/mount.c b/src/core/mount.c -index 23f63ce..4dc9f2e 100644 ---- a/src/core/mount.c -+++ b/src/core/mount.c -@@ -1883,6 +1883,14 @@ static const char* const mount_state_table[_MOUNT_STATE_MAX] = { - - DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); - -+static int mount_control_pid(Unit *u) { -+ Mount *m = MOUNT(u); -+ -+ assert(m); -+ -+ return m->control_pid; -+} -+ - static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { - [MOUNT_EXEC_MOUNT] = "ExecMount", - [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", -@@ -1944,6 +1952,8 @@ const UnitVTable mount_vtable = { - - .reset_failed = mount_reset_failed, - -+ .control_pid = mount_control_pid, -+ - .bus_interface = "org.freedesktop.systemd1.Mount", - .bus_vtable = bus_mount_vtable, - .bus_set_property = bus_mount_set_property, -diff --git a/src/core/service.c b/src/core/service.c -index ae5e610..f102ef3 100644 ---- a/src/core/service.c -+++ b/src/core/service.c -@@ -3028,6 +3028,22 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = { - - DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); - -+static int service_main_pid(Unit *u) { -+ Service *s = SERVICE(u); -+ -+ assert(s); -+ -+ return s->main_pid; -+} -+ -+static int service_control_pid(Unit *u) { -+ Service *s = SERVICE(u); -+ -+ assert(s); -+ -+ return s->control_pid; -+} -+ - static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { - [SERVICE_RESTART_NO] = "no", - [SERVICE_RESTART_ON_SUCCESS] = "on-success", -@@ -3138,6 +3154,9 @@ const UnitVTable service_vtable = { - .notify_cgroup_empty = service_notify_cgroup_empty_event, - .notify_message = service_notify_message, - -+ .main_pid = service_main_pid, -+ .control_pid = service_control_pid, -+ - .bus_name_owner_change = service_bus_name_owner_change, - - .bus_interface = "org.freedesktop.systemd1.Service", -diff --git a/src/core/socket.c b/src/core/socket.c -index bc677a2..771af0d 100644 ---- a/src/core/socket.c -+++ b/src/core/socket.c -@@ -2648,6 +2648,14 @@ static const char* const socket_state_table[_SOCKET_STATE_MAX] = { - - DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); - -+static int socket_control_pid(Unit *u) { -+ Socket *s = SOCKET(u); -+ -+ assert(s); -+ -+ return s->control_pid; -+} -+ - static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { - [SOCKET_EXEC_START_PRE] = "StartPre", - [SOCKET_EXEC_START_CHOWN] = "StartChown", -@@ -2713,6 +2721,8 @@ const UnitVTable socket_vtable = { - - .reset_failed = socket_reset_failed, - -+ .control_pid = socket_control_pid, -+ - .bus_interface = "org.freedesktop.systemd1.Socket", - .bus_vtable = bus_socket_vtable, - .bus_set_property = bus_socket_set_property, -diff --git a/src/core/swap.c b/src/core/swap.c -index 34a2c40..42f9959 100644 ---- a/src/core/swap.c -+++ b/src/core/swap.c -@@ -1426,6 +1426,14 @@ static const char* const swap_state_table[_SWAP_STATE_MAX] = { - - DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); - -+static int swap_control_pid(Unit *u) { -+ Swap *s = SWAP(u); -+ -+ assert(s); -+ -+ return s->control_pid; -+} -+ - static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { - [SWAP_EXEC_ACTIVATE] = "ExecActivate", - [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", -@@ -1487,6 +1495,8 @@ const UnitVTable swap_vtable = { - - .reset_failed = swap_reset_failed, - -+ .control_pid = swap_control_pid, -+ - .bus_interface = "org.freedesktop.systemd1.Swap", - .bus_vtable = bus_swap_vtable, - .bus_set_property = bus_swap_set_property, -diff --git a/src/core/unit.c b/src/core/unit.c -index 5b2becc..f03f185 100644 ---- a/src/core/unit.c -+++ b/src/core/unit.c -@@ -3667,6 +3667,24 @@ int unit_setup_exec_runtime(Unit *u) { - return exec_runtime_make(rt, unit_get_exec_context(u), u->id); - } - -+pid_t unit_control_pid(Unit *u) { -+ assert(u); -+ -+ if (UNIT_VTABLE(u)->control_pid) -+ return UNIT_VTABLE(u)->control_pid(u); -+ -+ return 0; -+} -+ -+pid_t unit_main_pid(Unit *u) { -+ assert(u); -+ -+ if (UNIT_VTABLE(u)->main_pid) -+ return UNIT_VTABLE(u)->main_pid(u); -+ -+ return 0; -+} -+ - static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { - [UNIT_ACTIVE] = "active", - [UNIT_RELOADING] = "reloading", -diff --git a/src/core/unit.h b/src/core/unit.h -index d936457..35287a5 100644 ---- a/src/core/unit.h -+++ b/src/core/unit.h -@@ -399,6 +399,12 @@ struct UnitVTable { - - int (*get_timeout)(Unit *u, uint64_t *timeout); - -+ /* Returns the main PID if there is any defined, or 0. */ -+ pid_t (*main_pid)(Unit *u); -+ -+ /* Returns the main PID if there is any defined, or 0. */ -+ pid_t (*control_pid)(Unit *u); -+ - /* This is called for each unit type and should be used to - * enumerate existing devices and load them. However, - * everything that is loaded here should still stay in -@@ -610,6 +616,9 @@ int unit_make_transient(Unit *u); - - int unit_require_mounts_for(Unit *u, const char *path); - -+pid_t unit_control_pid(Unit *u); -+pid_t unit_main_pid(Unit *u); -+ - const char *unit_active_state_to_string(UnitActiveState i) _const_; - UnitActiveState unit_active_state_from_string(const char *s) _pure_; - diff --git a/SOURCES/0285-udev-downgrade-a-few-warnings-to-debug-messages.patch b/SOURCES/0285-udev-downgrade-a-few-warnings-to-debug-messages.patch new file mode 100644 index 0000000..461de4d --- /dev/null +++ b/SOURCES/0285-udev-downgrade-a-few-warnings-to-debug-messages.patch @@ -0,0 +1,44 @@ +From 95a6f0f1b2a24e40380af5db1797ee60c8763ca2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 14 Apr 2015 15:48:26 +0200 +Subject: [PATCH] udev: downgrade a few warnings to debug messages + +https://bugs.freedesktop.org/show_bug.cgi?id=89885 + +Cherry-picked from: 8d8ce9e2 +Resolves: #1289461 +--- + src/udev/udev-builtin-blkid.c | 2 +- + src/udev/udev-builtin-usb_id.c | 6 ++---- + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c +index 8999583..2b2c3da 100644 +--- a/src/udev/udev-builtin-blkid.c ++++ b/src/udev/udev-builtin-blkid.c +@@ -263,7 +263,7 @@ static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool t + + fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC); + if (fd < 0) { +- fprintf(stderr, "error: %s: %m\n", udev_device_get_devnode(dev)); ++ err = log_debug_errno(errno, "Failure opening block device %s: %m", udev_device_get_devnode(dev)); + goto out; + } + +diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c +index ab0d96e..64b763c 100644 +--- a/src/udev/udev-builtin-usb_id.c ++++ b/src/udev/udev-builtin-usb_id.c +@@ -168,10 +168,8 @@ static int dev_if_packed_info(struct udev_device *dev, char *ifs_str, size_t len + return log_oom(); + + fd = open(filename, O_RDONLY|O_CLOEXEC); +- if (fd < 0) { +- fprintf(stderr, "error opening USB device 'descriptors' file\n"); +- return -errno; +- } ++ if (fd < 0) ++ return log_debug_errno(errno, "Error opening USB device 'descriptors' file: %m"); + + size = read(fd, buf, sizeof(buf)); + if (size < 18 || size == sizeof(buf)) diff --git a/SOURCES/0286-man-LEVEL-in-systemd-analyze-set-log-level-is-not-op.patch b/SOURCES/0286-man-LEVEL-in-systemd-analyze-set-log-level-is-not-op.patch new file mode 100644 index 0000000..7a72451 --- /dev/null +++ b/SOURCES/0286-man-LEVEL-in-systemd-analyze-set-log-level-is-not-op.patch @@ -0,0 +1,26 @@ +From ffe00d391c0cfc52897820bb19c6a0b8a43680d8 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 5 Oct 2015 12:19:13 +0200 +Subject: [PATCH] man: LEVEL in systemd-analyze set-log level is not optional + +rhbz#1268336 + +Cherry-picked from: 62b29f83cdd3059fda5bf5d2e098293f6dccf863 +Resolves: #1268336 +--- + man/systemd-analyze.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml +index b2e0f42..e58d9a7 100644 +--- a/man/systemd-analyze.xml ++++ b/man/systemd-analyze.xml +@@ -93,7 +93,7 @@ + systemd-analyze + OPTIONS + set-log-level +- LEVEL ++ LEVEL + + + systemd-analyze diff --git a/SOURCES/0287-Revert-udev-fibre-channel-fix-NPIV-support.patch b/SOURCES/0287-Revert-udev-fibre-channel-fix-NPIV-support.patch new file mode 100644 index 0000000..10170d9 --- /dev/null +++ b/SOURCES/0287-Revert-udev-fibre-channel-fix-NPIV-support.patch @@ -0,0 +1,57 @@ +From 4c895cb7bbb307f3c865d9a37f448605797d2b42 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 29 Feb 2016 16:33:38 +0100 +Subject: [PATCH] Revert "udev: fibre channel: fix NPIV support" + +This reverts commit 569d98e9caae425120bf28f6b440e6cc117abc0d. + +Related: #1266934 +--- + src/udev/udev-builtin-path_id.c | 27 +++------------------------ + 1 file changed, 3 insertions(+), 24 deletions(-) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 695ac7f..9ca6084 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -92,9 +92,6 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s + static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; +- struct udev_device *rportdev; +- struct udev_device *hostdev; +- struct udev_device *vportdev; + struct udev_device *fcdev = NULL; + const char *port; + char *lun = NULL; +@@ -103,27 +100,9 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, + if (targetdev == NULL) + return NULL; + +- rportdev = udev_device_get_parent(targetdev); +- if (rportdev == NULL) +- goto skip_npiv_check; +- +- hostdev = udev_device_get_parent(rportdev); +- if (hostdev == NULL) +- goto skip_npiv_check; +- +- vportdev = udev_device_get_parent(hostdev); +- if (vportdev == NULL) +- goto skip_npiv_check; +- +- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev)); +- +-skip_npiv_check: +- if (fcdev == NULL) { +- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); +- if (fcdev == NULL) +- return NULL; +- } +- ++ fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); ++ if (fcdev == NULL) ++ return NULL; + port = udev_device_get_sysattr_value(fcdev, "port_name"); + if (port == NULL) { + parent = NULL; diff --git a/SOURCES/0288-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch b/SOURCES/0288-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch new file mode 100644 index 0000000..f710d52 --- /dev/null +++ b/SOURCES/0288-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch @@ -0,0 +1,125 @@ +From 05004e584a76645dcbcaaa4d5c2d3d3255900770 Mon Sep 17 00:00:00 2001 +From: Mauricio Faria de Oliveira +Date: Tue, 23 Feb 2016 15:02:02 -0300 +Subject: [PATCH] udev: path-id: fibre channel NPIV - use fc_vport's port_name + +With the Fibre Channel NPIV (N_Port ID Virtualization) feature, +a single physical N_Port (e.g., PCI address) can have multiple +N_Port IDs (e.g., different fc_host nodes) - which can connect +to the same target LUN (e.g., fc_remote_port's port_name and +LUN number). + +Thus, in order to be unique, the device persistent path should +include the fc_vport's port_name (only if the fc_vport is used), +in addition to the already in use PCI address, fc_remote_port's +port_name and LUN number. + +The patch merges the 2 proposals submitted upstream, addressing +some problems with both: +- #2500 (don't replace the fc_rport's port_name with fc_vport's) +- #2665 (don't add a fc_host/fc_vport's port_name if not needed) + +Links +- https://github.com/systemd/systemd/pull/2500/ +- https://github.com/systemd/systemd/pull/2665/ + +Built, checked, tested on RHEL Server 7.1 with no regressions. + +With the patch, /dev/disk/by-path symlinks are created correctly, +and are unique, backward-compatible with the physical port case: +- physical port (no vport field) +- virtual ports (w/ vport field) + + # ls -l /dev/disk/by-path | grep 0001:09:00.0 + <...> pci-0001:09:00.0-fc-0x500507680b2255fe-lun-0 -> ../../sdh + <...> pci-0001:09:00.0-fc-0x500507680b2255ff-lun-0 -> ../../sdi + <...> pci-0001:09:00.0-vport-0x5001a4aaf00a6785-fc-0x500507680b2255fe-lun-0 -> ../../sde + <...> pci-0001:09:00.0-vport-0x5001a4aaf00a6785-fc-0x500507680b2255ff-lun-0 -> ../../sdd + <...> pci-0001:09:00.0-vport-0x5001a4ad99d8c2de-fc-0x500507680b2255fe-lun-0 -> ../../sdc + <...> pci-0001:09:00.0-vport-0x5001a4ad99d8c2de-fc-0x500507680b2255ff-lun-0 -> ../../sdb + +Accordingly w/ sysfs: + + # ls -ld /sys/block/sd* | grep host1 + <...> /sys/block/sdb -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-0/host3/rport-3:0-1/target3:0:0/3:0:0:0/block/sdb + <...> /sys/block/sdc -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-0/host3/rport-3:0-2/target3:0:1/3:0:1:0/block/sdc + <...> /sys/block/sdd -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-2/host5/rport-5:0-1/target5:0:0/5:0:0:0/block/sdd + <...> /sys/block/sde -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/vport-1:0-2/host5/rport-5:0-2/target5:0:1/5:0:1:0/block/sde + <...> /sys/block/sdh -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/rport-1:0-3/target1:0:0/1:0:0:0/block/sdh + <...> /sys/block/sdi -> ../devices/pci0001:00/<...>/0001:09:00.0/host1/rport-1:0-4/target1:0:1/1:0:1:0/block/sdi + +The symlinks still include the fc_remote_port's (target) port_name: + + # grep . /sys/class/fc_remote_ports/rport-{3:0-{1,2},5:0-{1,2},1:0-{3,4}}/port_name + /sys/class/fc_remote_ports/rport-3:0-1/port_name:0x500507680b2255ff + /sys/class/fc_remote_ports/rport-3:0-2/port_name:0x500507680b2255fe + /sys/class/fc_remote_ports/rport-5:0-1/port_name:0x500507680b2255ff + /sys/class/fc_remote_ports/rport-5:0-2/port_name:0x500507680b2255fe + /sys/class/fc_remote_ports/rport-1:0-3/port_name:0x500507680b2255fe + /sys/class/fc_remote_ports/rport-1:0-4/port_name:0x500507680b2255ff + +And now include the fc_vport's (virtual host) port_name *if* it's from a fc_vport: + + # grep . /sys/class/fc_host/host1/port_name /sys/class/fc_vports/vport-1:0-{0,2}/port_name + /sys/class/fc_host/host1/port_name:0x10000090fa8f0ebc + /sys/class/fc_vports/vport-1:0-0/port_name:0x5001a4ad99d8c2de + /sys/class/fc_vports/vport-1:0-2/port_name:0x5001a4aaf00a6785 + +Signed-off-by: Mauricio Faria de Oliveira +Reported-by: Srikanth B. Aithal + +Cherry-picked from: 6a3d3f9e5970cf982ac37c65d0b856146b675a12 +Resolves: #1266934 +--- + src/udev/udev-builtin-path_id.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 9ca6084..3b72922 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -92,7 +92,11 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s + static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) { + struct udev *udev = udev_device_get_udev(parent); + struct udev_device *targetdev; ++ struct udev_device *rportdev; ++ struct udev_device *hostdev; ++ struct udev_device *vportdev; + struct udev_device *fcdev = NULL; ++ struct udev_device *fc_vportdev = NULL; + const char *port; + char *lun = NULL; + +@@ -113,6 +117,32 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, + path_prepend(path, "fc-%s-%s", port, lun); + if (lun) + free(lun); ++ ++ /* NPIV */ ++ rportdev = udev_device_get_parent(targetdev); ++ if (rportdev == NULL) ++ goto out; ++ ++ hostdev = udev_device_get_parent(rportdev); ++ if (hostdev == NULL) ++ goto out; ++ ++ vportdev = udev_device_get_parent(hostdev); ++ if (vportdev == NULL) ++ goto out; ++ ++ fc_vportdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev)); ++ if (fc_vportdev == NULL) ++ goto out; ++ ++ port = udev_device_get_sysattr_value(fc_vportdev, "port_name"); ++ if (port == NULL) ++ goto out_npiv; ++ ++ path_prepend(path, "vport-%s", port); ++ ++out_npiv: ++ udev_device_unref(fc_vportdev); + out: + udev_device_unref(fcdev); + return parent; diff --git a/SOURCES/0289-systemctl-is-active-failed-should-return-0-if-at-lea.patch b/SOURCES/0289-systemctl-is-active-failed-should-return-0-if-at-lea.patch new file mode 100644 index 0000000..c421414 --- /dev/null +++ b/SOURCES/0289-systemctl-is-active-failed-should-return-0-if-at-lea.patch @@ -0,0 +1,45 @@ +From f3b1b4ae42a2d0d6383c6587a842418abad645a9 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 25 Jan 2016 15:21:28 +0100 +Subject: [PATCH] systemctl: is-active/failed should return 0 if at least one + unit is in given state + +Previously we have return the not-found code, in the case that we found a +unit which does not belong to set active (resp. failed), which is the +opposite than what is written in man page. + +Cherry-picked from: d60f6ad0cb690d920b8acbfb545bad29554609f1 +Resolves: #1254650 +--- + src/systemctl/systemctl.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 5d3a85f..bf5bb39 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -3002,6 +3002,7 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch + _cleanup_strv_free_ char **names = NULL; + char **name; + int r; ++ bool found = false; + + assert(bus); + assert(args); +@@ -3016,11 +3017,13 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch + state = check_one_unit(bus, *name, good_states, arg_quiet); + if (state < 0) + return state; +- if (state == 0) +- r = code; ++ if (state > 0) ++ found = true; + } + +- return r; ++ /* use the given return code for the case that we won't find ++ * any unit which matches the list */ ++ return found ? 0 : code; + } + + static int check_unit_active(sd_bus *bus, char **args) { diff --git a/SOURCES/0290-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch b/SOURCES/0290-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch new file mode 100644 index 0000000..7c60bfd --- /dev/null +++ b/SOURCES/0290-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch @@ -0,0 +1,34 @@ +From d77ced281c6d1f47b5dfc3abff6817d8f5756af9 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Thu, 25 Feb 2016 15:15:04 +0100 +Subject: [PATCH] rules: set SYSTEMD_READY=0 on + DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 only with ADD event + +The "SYSTEMD_READY=0" will cause automatic unmount +of mountpoint that is on top of such DM device +if this is used with multipath which sets +DM_UDEV_DISABLE_OTHER_RULES_FLAG in case +we have a CHANGE event thatcomes after DM multipath +device reload when one of the paths is down or up. + +See https://bugzilla.redhat.com/show_bug.cgi?id=1312011 + +Cherry-picked from: 83a3642f617975d596b5001b1699c3d16773a6e5 +Resolves: #1312011 +--- + rules/99-systemd.rules.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in +index b66d727..a4f4bf3 100644 +--- a/rules/99-systemd.rules.in ++++ b/rules/99-systemd.rules.in +@@ -12,7 +12,7 @@ SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*|3270 + KERNEL=="vport*", TAG+="systemd" + + SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd" +-SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" ++SUBSYSTEM=="block", KERNEL!="ram*", ACTION=="add", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" + + # Ignore encrypted devices with no identified superblock on it, since + # we are probably still calling mke2fs or mkswap on it. diff --git a/SOURCES/0291-s390-add-personality-support.patch b/SOURCES/0291-s390-add-personality-support.patch new file mode 100644 index 0000000..1e6fc33 --- /dev/null +++ b/SOURCES/0291-s390-add-personality-support.patch @@ -0,0 +1,109 @@ +From 9435bd3d692c7b07e527b6a616018fa5620502e2 Mon Sep 17 00:00:00 2001 +From: Hendrik Brueckner +Date: Thu, 24 Sep 2015 12:47:22 +0200 +Subject: [PATCH] s390: add personality support + +Introduce personality support for Linux on z Systems to run +particular services with a 64-bit or 31-bit personality. + +Cherry-picked from: 7517f51ef9921d3360453c8eec2c97256d320ceb +Resolves: #1300344 +--- + Makefile.am | 1 + + src/shared/util.c | 27 +++++++++++++++++++++++++++ + src/test/test-execute.c | 8 ++++++-- + test/exec-personality-s390.service | 7 +++++++ + 4 files changed, 41 insertions(+), 2 deletions(-) + create mode 100644 test/exec-personality-s390.service + +diff --git a/Makefile.am b/Makefile.am +index 2559376..3af720b 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1483,6 +1483,7 @@ EXTRA_DIST += \ + test/exec-ignoresigpipe-yes.service \ + test/exec-personality-x86-64.service \ + test/exec-personality-x86.service \ ++ test/exec-personality-s390.service \ + test/exec-privatedevices-no.service \ + test/exec-privatedevices-yes.service \ + test/exec-privatetmp-no.service \ +diff --git a/src/shared/util.c b/src/shared/util.c +index dc51852..a24aa7f 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -6748,6 +6748,19 @@ unsigned long personality_from_string(const char *p) { + + if (streq(p, "x86")) + return PER_LINUX; ++ ++#elif defined(__s390x__) ++ ++ if (streq(p, "s390")) ++ return PER_LINUX32; ++ ++ if (streq(p, "s390x")) ++ return PER_LINUX; ++ ++#elif defined(__s390__) ++ ++ if (streq(p, "s390")) ++ return PER_LINUX; + #endif + + /* personality(7) documents that 0xffffffffUL is used for +@@ -6770,6 +6783,20 @@ const char* personality_to_string(unsigned long p) { + + if (p == PER_LINUX) + return "x86"; ++ ++#elif defined(__s390x__) ++ ++ if (p == PER_LINUX) ++ return "s390x"; ++ ++ if (p == PER_LINUX32) ++ return "s390"; ++ ++#elif defined(__s390__) ++ ++ if (p == PER_LINUX) ++ return "s390"; ++ + #endif + + return NULL; +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 91ccaf7..00f3607 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -77,10 +77,14 @@ static void test_exec_workingdirectory(Manager *m) { + } + + static void test_exec_personality(Manager *m) { +- test(m, "exec-personality-x86.service", 0, CLD_EXITED); +- + #if defined(__x86_64__) + test(m, "exec-personality-x86-64.service", 0, CLD_EXITED); ++ ++#elif defined(__s390__) ++ test(m, "exec-personality-s390.service", 0, CLD_EXITED); ++ ++#else ++ test(m, "exec-personality-x86.service", 0, CLD_EXITED); + #endif + } + +diff --git a/test/exec-personality-s390.service b/test/exec-personality-s390.service +new file mode 100644 +index 0000000..f3c3b03 +--- /dev/null ++++ b/test/exec-personality-s390.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for Personality=s390 ++ ++[Service] ++ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "s390")' ++Type=oneshot ++Personality=s390 diff --git a/SOURCES/0292-socket_address_listen-do-not-rely-on-errno.patch b/SOURCES/0292-socket_address_listen-do-not-rely-on-errno.patch new file mode 100644 index 0000000..22eeeb3 --- /dev/null +++ b/SOURCES/0292-socket_address_listen-do-not-rely-on-errno.patch @@ -0,0 +1,34 @@ +From 2ae0271ada810c06c12755699f0db955fc51061d Mon Sep 17 00:00:00 2001 +From: Petr Lautrbach +Date: Thu, 10 Mar 2016 10:19:56 +0100 +Subject: [PATCH] socket_address_listen - do not rely on errno + +Currently socket_address_listen() calls mac_selinux_bind() to bind a UNIX +socket and checks its return value and errno for EADDRINUSE. This is not +correct. When there's an SELinux context change made for the new socket, +bind() is not the last function called in mac_selinux_bind(). In that +case the last call is setfscreatecon() from libselinux which can change +errno as it uses access() to check if /proc/thread-self is available. +It fails on kernels before 3.17 and errno is set to ENOENT. + +It's safe to check only the return value at it's set to -errno. + +Cherry-picked from: a0c9496cc826957fe0f3926f619e073f17a9ab4d +Resolves: #1316452 +--- + src/shared/socket-label.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c +index a6289eb..713e71b 100644 +--- a/src/shared/socket-label.c ++++ b/src/shared/socket-label.c +@@ -119,7 +119,7 @@ int socket_address_listen( + + r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); + +- if (r < 0 && errno == EADDRINUSE) { ++ if (r == -EADDRINUSE) { + /* Unlink and try again */ + unlink(a->sockaddr.un.sun_path); + r = bind(fd, &a->sockaddr.sa, a->size); diff --git a/SOURCES/0293-path_id-reintroduce-by-path-links-for-virtio-block-d.patch b/SOURCES/0293-path_id-reintroduce-by-path-links-for-virtio-block-d.patch new file mode 100644 index 0000000..318baa7 --- /dev/null +++ b/SOURCES/0293-path_id-reintroduce-by-path-links-for-virtio-block-d.patch @@ -0,0 +1,48 @@ +From b6fea1a0e0fd830e1aa82accf389cb8bfd0f0f37 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 9 Feb 2016 09:57:45 +0100 +Subject: [PATCH] path_id: reintroduce by-path links for virtio block devices + +Enumeration of virtio buses is global and hence +non-deterministic. However, we are guaranteed there is never going to be +more than one virtio bus per parent PCI device. While populating +ID_PATH we simply skip virtio part of the syspath and we extend the path +using the sysname of the parent PCI device. + +With this patch udev creates following by-path links for virtio-blk +device /dev/vda which contains two partitions. + +ls -l /dev/disk/by-path/ +total 0 +lrwxrwxrwx 1 root root 9 Feb 9 10:47 virtio-pci-0000:00:05.0 -> ../../vda +lrwxrwxrwx 1 root root 10 Feb 9 10:47 virtio-pci-0000:00:05.0-part1 -> ../../vda1 +lrwxrwxrwx 1 root root 10 Feb 9 10:47 virtio-pci-0000:00:05.0-part2 -> ../../vda2 + +See: +http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030328.html + +Fixes #2501 + +Cherry-picked from: f073b1b3c0f4f0df1b0bd61042ce85fb5d27d407 +Resolves: #952567 +--- + src/udev/udev-builtin-path_id.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 3b72922..8359e23 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -698,6 +698,12 @@ restart: + path_prepend(&path, "xen-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "xen"); + supported_parent = true; ++ } else if (streq(subsys, "virtio")) { ++ while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent))) ++ parent = udev_device_get_parent(parent); ++ path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent)); ++ supported_transport = true; ++ supported_parent = true; + } else if (streq(subsys, "scm")) { + path_prepend(&path, "scm-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "scm"); diff --git a/SOURCES/0294-journal-fix-error-handling-when-compressing-journal-.patch b/SOURCES/0294-journal-fix-error-handling-when-compressing-journal-.patch new file mode 100644 index 0000000..b5246a5 --- /dev/null +++ b/SOURCES/0294-journal-fix-error-handling-when-compressing-journal-.patch @@ -0,0 +1,67 @@ +From f45b66a348f5778bd391ad1b0a0e09bf5789b415 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Sat, 24 Oct 2015 13:17:54 +0200 +Subject: [PATCH] journal: fix error handling when compressing journal objects + +Let's make sure we handle compression errors properly, and don't +misunderstand an error for success. + +Also, let's actually compress things if lz4 is enabled. + +Fixes #1662. + +Cherry-picked from: d1afbcd22170e95c79261340071d376fe41fc3af +Resolves: #1292447 +--- + src/journal/journal-file.c | 12 +++++++----- + src/journal/journal-file.h | 5 +++++ + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index f500568..a8f92e2 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -1051,23 +1051,25 @@ static int journal_file_append_data( + o->data.hash = htole64(hash); + + #if defined(HAVE_XZ) || defined(HAVE_LZ4) +- if (f->compress_xz && +- size >= COMPRESSION_SIZE_THRESHOLD) { ++ if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) { + size_t rsize; + + compression = compress_blob(data, size, o->data.payload, &rsize); + +- if (compression) { ++ if (compression >= 0) { + o->object.size = htole64(offsetof(Object, data.payload) + rsize); + o->object.flags |= compression; + + log_debug("Compressed data object %"PRIu64" -> %zu using %s", + size, rsize, object_compressed_to_string(compression)); +- } ++ } else ++ /* Compression didn't work, we don't really care why, let's continue without compression */ ++ compression = 0; ++ + } + #endif + +- if (!compression && size > 0) ++ if (compression == 0 && size > 0) + memcpy(o->data.payload, data, size); + + r = journal_file_link_data(f, o, p, hash); +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index 403c8f7..0f29b09 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -229,3 +229,8 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t * + int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to); + + bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec); ++ ++static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) { ++ assert(f); ++ return f->compress_xz || f->compress_lz4; ++} diff --git a/SOURCES/0295-journal-irrelevant-coding-style-fixes.patch b/SOURCES/0295-journal-irrelevant-coding-style-fixes.patch new file mode 100644 index 0000000..db97ef0 --- /dev/null +++ b/SOURCES/0295-journal-irrelevant-coding-style-fixes.patch @@ -0,0 +1,45 @@ +From d205f5f85569e2dddca96362ce2db4e2a0b99d00 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Sat, 24 Oct 2015 15:08:15 +0200 +Subject: [PATCH] journal: irrelevant coding style fixes + +Cherry-picked from: 0240c603691e006165d8687d6a2c70859755b11f +Related: #1292447 +--- + src/journal/compress.c | 9 +++++---- + src/journal/journal-file.c | 2 +- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/src/journal/compress.c b/src/journal/compress.c +index 6923753..c9a3399 100644 +--- a/src/journal/compress.c ++++ b/src/journal/compress.c +@@ -51,10 +51,11 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_ + #ifdef HAVE_XZ + static const lzma_options_lzma opt = { + 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT, +- LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4}; +- static const lzma_filter filters[2] = { +- {LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt}, +- {LZMA_VLI_UNKNOWN, NULL} ++ LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4 ++ }; ++ static const lzma_filter filters[] = { ++ { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt }, ++ { LZMA_VLI_UNKNOWN, NULL } + }; + lzma_ret ret; + size_t out_pos = 0; +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index a8f92e2..892fe47 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -1032,7 +1032,7 @@ static int journal_file_append_data( + r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p); + if (r < 0) + return r; +- else if (r > 0) { ++ if (r > 0) { + + if (ret) + *ret = o; diff --git a/SOURCES/0296-install-follow-unit-file-symlinks-in-usr-but-not-etc.patch b/SOURCES/0296-install-follow-unit-file-symlinks-in-usr-but-not-etc.patch new file mode 100644 index 0000000..21d90a8 --- /dev/null +++ b/SOURCES/0296-install-follow-unit-file-symlinks-in-usr-but-not-etc.patch @@ -0,0 +1,4358 @@ +From 272378080241106862a9cca2e4e84857fe1aaf5c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 8 Oct 2015 22:31:56 +0200 +Subject: [PATCH] install: follow unit file symlinks in /usr, but not /etc when + looking for [Install] data + +Some distributions use alias unit files via symlinks in /usr to cover +for legacy service names. With this change we'll allow "systemctl +enable" on such aliases. + +Previously, our rule was that symlinks are user configuration that +"systemctl enable" + "systemctl disable" creates and removes, while unit +files is where the instructions to do so are store. As a result of the +rule we'd never read install information through symlinks, since that +would mix enablement state with installation instructions. + +Now, the new rule is that only symlinks inside of /etc are +configuration. Unit files, and symlinks in /usr are now valid for +installation instructions. + +This patch is quite a rework of the whole install logic, and makes the +following addional changes: + +- Adds a complete test "test-instal-root" that tests the install logic + pretty comprehensively. + +- Never uses canonicalize_file_name(), because that's incompatible with + operation relative to a specific root directory. + +- unit_file_get_state() is reworked to return a proper error, and + returns the state in a call-by-ref parameter. This cleans up confusion + between the enum type and errno-like errors. + +- The new logic puts a limit on how long to follow unit file symlinks: + it will do so only for 64 steps at max. + +- The InstallContext object's fields are renamed to will_process and + has_processed (will_install and has_installed) since they are also + used for deinstallation and all kinds of other operations. + +- The root directory is always verified before use. + +- install.c is reordered to place the exported functions together. + +- Stricter rules are followed when traversing symlinks: the unit suffix + must say identical, and it's not allowed to link between regular units + and templated units. + +- Various modernizations + +- The "invalid" unit file state has been renamed to "bad", in order to + avoid confusion between UNIT_FILE_INVALID and + _UNIT_FILE_STATE_INVALID. Given that the state should normally not be + seen and is not documented this should not be a problematic change. + The new name is now documented however. + +Fixes #1375, #1718, #1706 + +Cherry-picked from: 79413b673b45adc98dfeaec882bbdda2343cb2f9 +Resolves: #1159308 +--- + Makefile.am | 12 +- + man/systemctl.xml | 14 +- + src/core/dbus-manager.c | 6 +- + src/core/dbus-unit.c | 4 +- + src/core/load-fragment.c | 2 +- + src/core/manager.c | 2 +- + src/core/snapshot.c | 2 +- + src/core/unit.c | 19 +- + src/dbus1-generator/dbus1-generator.c | 2 +- + src/firstboot/firstboot.c | 18 +- + src/shared/cgroup-util.c | 6 +- + src/shared/install.c | 1909 +++++++++++++++++++-------------- + src/shared/install.h | 46 +- + src/shared/path-util.c | 34 + + src/shared/path-util.h | 27 + + src/shared/unit-name.c | 32 +- + src/shared/unit-name.h | 14 +- + src/shared/util.c | 21 + + src/shared/util.h | 1 + + src/systemctl/systemctl.c | 6 +- + src/sysv-generator/sysv-generator.c | 10 +- + src/test/test-install-root.c | 663 ++++++++++++ + src/test/test-install.c | 71 +- + 23 files changed, 1998 insertions(+), 923 deletions(-) + create mode 100644 src/test/test-install-root.c + +diff --git a/Makefile.am b/Makefile.am +index 3af720b..3a09e0a 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1427,7 +1427,8 @@ tests += \ + test-copy \ + test-cap-list \ + test-sigbus \ +- test-verbs ++ test-verbs \ ++ test-install-root + + EXTRA_DIST += \ + test/a.service \ +@@ -1721,6 +1722,15 @@ test_verbs_SOURCES = \ + test_verbs_LDADD = \ + libsystemd-shared.la + ++test_install_root_SOURCES = \ ++ src/test/test-install-root.c ++ ++test_install_root_LDADD = \ ++ libsystemd-units.la \ ++ libsystemd-label.la \ ++ libsystemd-internal.la \ ++ libsystemd-shared.la ++ + test_namespace_LDADD = \ + libsystemd-core.la + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index c6f5842..2d0678d 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -905,10 +905,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + list-unit-files PATTERN... + + +- List installed unit files. If one or more +- PATTERNs are specified, only +- units whose filename (just the last component of the path) +- matches one of them are shown. ++ List installed unit files and their enablement state ++ (as reported by is-enabled). If one or ++ more PATTERNs are specified, ++ only units whose filename (just the last component of the ++ path) matches one of them are shown. + + + +@@ -1108,6 +1109,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + Unit file is not enabled. + 1 + ++ ++ bad ++ Unit file is invalid or another error occured. Note that is-enabled wil not actually return this state, but print an error message instead. However the unit file listing printed by list-unit-files might show it. ++ > 0 ++ + + + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 1ec350e..faa124d 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1530,9 +1530,9 @@ static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void + + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + +- state = unit_file_get_state(scope, NULL, name); +- if (state < 0) +- return state; ++ r = unit_file_get_state(scope, NULL, name, &state); ++ if (r < 0) ++ return r; + + return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state)); + } +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 625d21a..227915e 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -919,7 +919,7 @@ static int bus_unit_set_transient_property( + if (r < 0) + return r; + +- if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice")) ++ if (!unit_name_is_valid(s, UNIT_NAME_PLAIN) || !endswith(s, ".slice")) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s); + + if (isempty(s)) { +@@ -967,7 +967,7 @@ static int bus_unit_set_transient_property( + return r; + + while ((r = sd_bus_message_read(message, "s", &other)) > 0) { +- if (!unit_name_is_valid(other, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other); + + if (mode != UNIT_CHECK) { +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index ec4cf4e..70c0918 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3409,7 +3409,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { + * unit name. */ + name = basename(*filename); + +- if (unit_name_is_valid(name, TEMPLATE_VALID)) { ++ if (unit_name_is_valid(name, UNIT_NAME_ANY)) { + + id = set_get(names, name); + if (!id) { +diff --git a/src/core/manager.c b/src/core/manager.c +index 7483a96..bde17ce 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1328,7 +1328,7 @@ int manager_load_unit_prepare( + + t = unit_name_to_type(name); + +- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, TEMPLATE_INVALID)) ++ if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); + + ret = manager_get_unit(m, name); +diff --git a/src/core/snapshot.c b/src/core/snapshot.c +index b1d8448..f222ec2 100644 +--- a/src/core/snapshot.c ++++ b/src/core/snapshot.c +@@ -201,7 +201,7 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, + assert(_s); + + if (name) { +- if (!unit_name_is_valid(name, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(name, UNIT_NAME_PLAIN)) + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); + + if (unit_name_to_type(name) != UNIT_SNAPSHOT) +diff --git a/src/core/unit.c b/src/core/unit.c +index 4fb2fd3..db5aa98 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -158,7 +158,7 @@ int unit_add_name(Unit *u, const char *text) { + if (!s) + return -ENOMEM; + +- if (!unit_name_is_valid(s, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(s, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return -EINVAL; + + assert_se((t = unit_name_to_type(s)) >= 0); +@@ -3119,12 +3119,18 @@ int unit_following_set(Unit *u, Set **s) { + } + + UnitFileState unit_get_unit_file_state(Unit *u) { ++ int r; ++ + assert(u); + +- if (u->unit_file_state < 0 && u->fragment_path) +- u->unit_file_state = unit_file_get_state( +- u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, +- NULL, basename(u->fragment_path)); ++ if (u->unit_file_state < 0 && u->fragment_path) { ++ r = unit_file_get_state(u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, ++ NULL, ++ basename(u->fragment_path), ++ &u->unit_file_state); ++ if (r < 0) ++ u->unit_file_state = UNIT_FILE_BAD; ++ } + + return u->unit_file_state; + } +@@ -3135,7 +3141,8 @@ int unit_get_unit_file_preset(Unit *u) { + if (u->unit_file_preset < 0 && u->fragment_path) + u->unit_file_preset = unit_file_query_preset( + u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, +- NULL, basename(u->fragment_path)); ++ NULL, ++ basename(u->fragment_path)); + + return u->unit_file_preset; + } +diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c +index 2e08af2..c909a4b 100644 +--- a/src/dbus1-generator/dbus1-generator.c ++++ b/src/dbus1-generator/dbus1-generator.c +@@ -188,7 +188,7 @@ static int add_dbus(const char *path, const char *fname, const char *type) { + } + + if (service) { +- if (!unit_name_is_valid(service, TEMPLATE_INVALID)) { ++ if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { + log_warning("Unit name %s is not valid, ignoring.", service); + return 0; + } +diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c +index a37ca17..b77c1d8 100644 +--- a/src/firstboot/firstboot.c ++++ b/src/firstboot/firstboot.c +@@ -50,8 +50,6 @@ static bool arg_copy_locale = false; + static bool arg_copy_timezone = false; + static bool arg_copy_root_password = false; + +-#define prefix_roota(p) (arg_root ? (const char*) strjoina(arg_root, p) : (const char*) p) +- + static void clear_string(char *x) { + + if (!x) +@@ -85,13 +83,13 @@ static void print_welcome(void) { + if (done) + return; + +- os_release = prefix_roota("/etc/os-release"); ++ os_release = prefix_roota(arg_root, "/etc/os-release"); + r = parse_env_file(os_release, NEWLINE, + "PRETTY_NAME", &pretty_name, + NULL); + if (r == -ENOENT) { + +- os_release = prefix_roota("/usr/lib/os-release"); ++ os_release = prefix_roota(arg_root, "/usr/lib/os-release"); + r = parse_env_file(os_release, NEWLINE, + "PRETTY_NAME", &pretty_name, + NULL); +@@ -249,7 +247,7 @@ static int process_locale(void) { + unsigned i = 0; + int r; + +- etc_localeconf = prefix_roota("/etc/locale.conf"); ++ etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf"); + if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -323,7 +321,7 @@ static int process_timezone(void) { + const char *etc_localtime, *e; + int r; + +- etc_localtime = prefix_roota("/etc/localtime"); ++ etc_localtime = prefix_roota(arg_root, "/etc/localtime"); + if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -402,7 +400,7 @@ static int process_hostname(void) { + const char *etc_hostname; + int r; + +- etc_hostname = prefix_roota("/etc/hostname"); ++ etc_hostname = prefix_roota(arg_root, "/etc/hostname"); + if (faccessat(AT_FDCWD, etc_hostname, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -427,7 +425,7 @@ static int process_machine_id(void) { + char id[SD_ID128_STRING_MAX]; + int r; + +- etc_machine_id = prefix_roota("/etc/machine-id"); ++ etc_machine_id = prefix_roota(arg_root, "/etc/machine-id"); + if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -453,7 +451,7 @@ static int prompt_root_password(void) { + if (!arg_prompt_root_password) + return 0; + +- etc_shadow = prefix_roota("/etc/shadow"); ++ etc_shadow = prefix_roota(arg_root, "/etc/shadow"); + if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +@@ -542,7 +540,7 @@ static int process_root_password(void) { + const char *etc_shadow; + int r; + +- etc_shadow = prefix_roota("/etc/shadow"); ++ etc_shadow = prefix_roota(arg_root, "/etc/shadow"); + if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + return 0; + +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index dfd8689..cf757d2 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -1147,7 +1147,7 @@ int cg_path_decode_unit(const char *cgroup, char **unit){ + c = strndupa(cgroup, e - cgroup); + c = cg_unescape(c); + +- if (!unit_name_is_valid(c, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return -EINVAL; + + s = strdup(c); +@@ -1536,7 +1536,7 @@ int cg_slice_to_path(const char *unit, char **ret) { + assert(unit); + assert(ret); + +- if (!unit_name_is_valid(unit, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN)) + return -EINVAL; + + if (!endswith(unit, ".slice")) +@@ -1553,7 +1553,7 @@ int cg_slice_to_path(const char *unit, char **ret) { + + strcpy(stpncpy(n, p, dash - p), ".slice"); + +- if (!unit_name_is_valid(n, TEMPLATE_INVALID)) ++ if (!unit_name_is_valid(n, UNIT_NAME_PLAIN)) + return -EINVAL; + + escaped = cg_escape(n); +diff --git a/src/shared/install.c b/src/shared/install.c +index aa197e9..5288bb4 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -39,15 +39,24 @@ + #include "specifier.h" + #include "install-printf.h" + #include "special.h" ++#include "fileio.h" ++ ++#define UNIT_FILE_FOLLOW_SYMLINK_MAX 64 ++ ++typedef enum SearchFlags { ++ SEARCH_LOAD = 1, ++ SEARCH_FOLLOW_CONFIG_SYMLINKS = 2, ++} SearchFlags; + + typedef struct { +- OrderedHashmap *will_install; +- OrderedHashmap *have_installed; ++ OrderedHashmap *will_process; ++ OrderedHashmap *have_processed; + } InstallContext; + + static int in_search_path(const char *path, char **search) { + _cleanup_free_ char *parent = NULL; + int r; ++ char **i; + + assert(path); + +@@ -55,7 +64,11 @@ static int in_search_path(const char *path, char **search) { + if (r < 0) + return r; + +- return strv_contains(search, parent); ++ STRV_FOREACH(i, search) ++ if (path_equal(parent, *i)) ++ return true; ++ ++ return false; + } + + static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) { +@@ -66,6 +79,9 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(ret); + ++ /* This determines where we shall create or remove our ++ * installation ("configuration") symlinks */ ++ + switch (scope) { + + case UNIT_FILE_SYSTEM: +@@ -113,6 +129,186 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d + return 0; + } + ++static bool is_config_path(UnitFileScope scope, const char *path) { ++ int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(path); ++ ++ /* Checks whether the specified path is intended for ++ * configuration or is outside of it */ ++ ++ switch (scope) { ++ ++ case UNIT_FILE_SYSTEM: ++ case UNIT_FILE_GLOBAL: ++ return path_startswith(path, "/etc") || ++ path_startswith(path, SYSTEM_CONFIG_UNIT_PATH) || ++ path_startswith(path, "/run"); ++ ++ ++ case UNIT_FILE_USER: { ++ _cleanup_free_ char *p = NULL; ++ ++ r = user_config_home(&p); ++ if (r < 0) ++ return r; ++ if (r > 0 && path_startswith(path, p)) ++ return true; ++ ++ free(p); ++ p = NULL; ++ ++ r = user_runtime_dir(&p); ++ if (r < 0) ++ return r; ++ if (r > 0 && path_startswith(path, p)) ++ return true; ++ ++ return false; ++ } ++ ++ default: ++ assert_not_reached("Bad scope"); ++ } ++} ++ ++ ++static int verify_root_dir(UnitFileScope scope, const char **root_dir) { ++ int r; ++ ++ assert(root_dir); ++ ++ /* Verifies that the specified root directory to operate on ++ * makes sense. Reset it to NULL if it is the root directory ++ * or set to empty */ ++ ++ if (isempty(*root_dir) || path_equal(*root_dir, "/")) { ++ *root_dir = NULL; ++ return 0; ++ } ++ ++ if (scope != UNIT_FILE_SYSTEM) ++ return -EINVAL; ++ ++ r = is_dir(*root_dir, true); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return -ENOTDIR; ++ ++ return 0; ++} ++ ++int unit_file_changes_add( ++ UnitFileChange **changes, ++ unsigned *n_changes, ++ UnitFileChangeType type, ++ const char *path, ++ const char *source) { ++ ++ UnitFileChange *c; ++ unsigned i; ++ ++ assert(path); ++ assert(!changes == !n_changes); ++ ++ if (!changes) ++ return 0; ++ ++ c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); ++ if (!c) ++ return -ENOMEM; ++ ++ *changes = c; ++ i = *n_changes; ++ ++ c[i].type = type; ++ c[i].path = strdup(path); ++ if (!c[i].path) ++ return -ENOMEM; ++ ++ path_kill_slashes(c[i].path); ++ ++ if (source) { ++ c[i].source = strdup(source); ++ if (!c[i].source) { ++ free(c[i].path); ++ return -ENOMEM; ++ } ++ ++ path_kill_slashes(c[i].path); ++ } else ++ c[i].source = NULL; ++ ++ *n_changes = i+1; ++ return 0; ++} ++ ++void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { ++ unsigned i; ++ ++ assert(changes || n_changes == 0); ++ ++ if (!changes) ++ return; ++ ++ for (i = 0; i < n_changes; i++) { ++ free(changes[i].path); ++ free(changes[i].source); ++ } ++ ++ free(changes); ++} ++ ++static int create_symlink( ++ const char *old_path, ++ const char *new_path, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { ++ ++ _cleanup_free_ char *dest = NULL; ++ int r; ++ ++ assert(old_path); ++ assert(new_path); ++ ++ /* Actually create a symlink, and remember that we did. Is ++ * smart enough to check if there's already a valid symlink in ++ * place. */ ++ ++ mkdir_parents_label(new_path, 0755); ++ ++ if (symlink(old_path, new_path) >= 0) { ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); ++ return 0; ++ } ++ ++ if (errno != EEXIST) ++ return -errno; ++ ++ r = readlink_malloc(new_path, &dest); ++ if (r < 0) ++ return r; ++ ++ if (path_equal(dest, old_path)) ++ return 0; ++ ++ if (!force) ++ return -EEXIST; ++ ++ r = symlink_atomic(old_path, new_path); ++ if (r < 0) ++ return r; ++ ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); ++ ++ return 0; ++} ++ + static int mark_symlink_for_removal( + Set **remove_symlinks_to, + const char *p) { +@@ -136,7 +332,7 @@ static int mark_symlink_for_removal( + if (r < 0) + return r == -EEXIST ? 0 : r; + +- return 0; ++ return 1; + } + + static int remove_marked_symlinks_fd( +@@ -144,10 +340,9 @@ static int remove_marked_symlinks_fd( + int fd, + const char *path, + const char *config_path, +- bool *deleted, ++ bool *restart, + UnitFileChange **changes, +- unsigned *n_changes, +- char** instance_whitelist) { ++ unsigned *n_changes) { + + _cleanup_closedir_ DIR *d = NULL; + int r = 0; +@@ -156,7 +351,7 @@ static int remove_marked_symlinks_fd( + assert(fd >= 0); + assert(path); + assert(config_path); +- assert(deleted); ++ assert(restart); + + d = fdopendir(fd); + if (!d) { +@@ -205,42 +400,23 @@ static int remove_marked_symlinks_fd( + } + + /* This will close nfd, regardless whether it succeeds or not */ +- q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, instance_whitelist); ++ q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes); + if (q < 0 && r == 0) + r = q; + + } else if (de->d_type == DT_LNK) { + _cleanup_free_ char *p = NULL, *dest = NULL; +- int q; + bool found; ++ int q; + +- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) + continue; + +- if (unit_name_is_instance(de->d_name) && +- instance_whitelist && +- !strv_contains(instance_whitelist, de->d_name)) { +- +- _cleanup_free_ char *w; +- +- /* OK, the file is not listed directly +- * in the whitelist, so let's check if +- * the template of it might be +- * listed. */ +- +- w = unit_name_template(de->d_name); +- if (!w) +- return -ENOMEM; +- +- if (!strv_contains(instance_whitelist, w)) +- continue; +- } +- + p = path_make_absolute(de->d_name, path); + if (!p) + return -ENOMEM; + +- q = readlink_and_canonicalize(p, &dest); ++ q = readlink_malloc(p, &dest); + if (q < 0) { + if (q == -ENOENT) + continue; +@@ -250,9 +426,15 @@ static int remove_marked_symlinks_fd( + continue; + } + ++ /* We remove all links pointing to a file or ++ * path that is marked, as well as all files ++ * sharing the same name as a file that is ++ * marked. */ ++ + found = +- set_get(remove_symlinks_to, dest) || +- set_get(remove_symlinks_to, basename(dest)); ++ set_contains(remove_symlinks_to, dest) || ++ set_contains(remove_symlinks_to, basename(dest)) || ++ set_contains(remove_symlinks_to, de->d_name); + + if (!found) + continue; +@@ -264,18 +446,15 @@ static int remove_marked_symlinks_fd( + } + + path_kill_slashes(p); +- rmdir_parents(p, config_path); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); ++ (void) rmdir_parents(p, config_path); + +- if (!set_get(remove_symlinks_to, p)) { ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); + +- q = mark_symlink_for_removal(&remove_symlinks_to, p); +- if (q < 0) { +- if (r == 0) +- r = q; +- } else +- *deleted = true; +- } ++ q = mark_symlink_for_removal(&remove_symlinks_to, p); ++ if (q < 0) ++ return q; ++ if (q > 0) ++ *restart = true; + } + } + +@@ -286,12 +465,11 @@ static int remove_marked_symlinks( + Set *remove_symlinks_to, + const char *config_path, + UnitFileChange **changes, +- unsigned *n_changes, +- char** instance_whitelist) { ++ unsigned *n_changes) { + + _cleanup_close_ int fd = -1; + int r = 0; +- bool deleted; ++ bool restart; + + assert(config_path); + +@@ -304,7 +482,7 @@ static int remove_marked_symlinks( + + do { + int q, cfd; +- deleted = false; ++ restart = false; + + cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (cfd < 0) { +@@ -313,15 +491,16 @@ static int remove_marked_symlinks( + } + + /* This takes possession of cfd and closes it */ +- q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, instance_whitelist); ++ q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes); + if (r == 0) + r = q; +- } while (deleted); ++ } while (restart); + + return r; + } + + static int find_symlinks_fd( ++ const char *root_dir, + const char *name, + int fd, + const char *path, +@@ -380,7 +559,7 @@ static int find_symlinks_fd( + } + + /* This will close nfd, regardless whether it succeeds or not */ +- q = find_symlinks_fd(name, nfd, p, config_path, same_name_link); ++ q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link); + if (q > 0) + return 1; + if (r == 0) +@@ -397,7 +576,7 @@ static int find_symlinks_fd( + return -ENOMEM; + + /* Acquire symlink destination */ +- q = readlink_and_canonicalize(p, &dest); ++ q = readlink_malloc(p, &dest); + if (q < 0) { + if (q == -ENOENT) + continue; +@@ -407,6 +586,18 @@ static int find_symlinks_fd( + continue; + } + ++ /* Make absolute */ ++ if (!path_is_absolute(dest)) { ++ char *x; ++ ++ x = prefix_root(root_dir, dest); ++ if (!x) ++ return -ENOMEM; ++ ++ free(dest); ++ dest = x; ++ } ++ + /* Check if the symlink itself matches what we + * are looking for */ + if (path_is_absolute(name)) +@@ -442,6 +633,7 @@ static int find_symlinks_fd( + } + + static int find_symlinks( ++ const char *root_dir, + const char *name, + const char *config_path, + bool *same_name_link) { +@@ -460,7 +652,7 @@ static int find_symlinks( + } + + /* This takes possession of fd and closes it */ +- return find_symlinks_fd(name, fd, config_path, config_path, same_name_link); ++ return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link); + } + + static int find_symlinks_in_scope( +@@ -469,385 +661,104 @@ static int find_symlinks_in_scope( + const char *name, + UnitFileState *state) { + +- int r; + _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL; + bool same_name_link_runtime = false, same_name_link = false; ++ int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- /* First look in runtime config path */ +- r = get_config_path(scope, true, root_dir, &normal_path); ++ /* First look in the normal config path */ ++ r = get_config_path(scope, false, root_dir, &normal_path); + if (r < 0) + return r; + +- r = find_symlinks(name, normal_path, &same_name_link_runtime); ++ r = find_symlinks(root_dir, name, normal_path, &same_name_link); + if (r < 0) + return r; +- else if (r > 0) { +- *state = UNIT_FILE_ENABLED_RUNTIME; ++ if (r > 0) { ++ *state = UNIT_FILE_ENABLED; + return r; + } + +- /* Then look in the normal config path */ +- r = get_config_path(scope, false, root_dir, &runtime_path); ++ /* Then look in runtime config path */ ++ r = get_config_path(scope, true, root_dir, &runtime_path); + if (r < 0) + return r; + +- r = find_symlinks(name, runtime_path, &same_name_link); ++ r = find_symlinks(root_dir, name, runtime_path, &same_name_link_runtime); + if (r < 0) + return r; +- else if (r > 0) { +- *state = UNIT_FILE_ENABLED; ++ if (r > 0) { ++ *state = UNIT_FILE_ENABLED_RUNTIME; + return r; + } + + /* Hmm, we didn't find it, but maybe we found the same name + * link? */ ++ if (same_name_link) { ++ *state = UNIT_FILE_LINKED; ++ return 1; ++ } + if (same_name_link_runtime) { + *state = UNIT_FILE_LINKED_RUNTIME; + return 1; +- } else if (same_name_link) { +- *state = UNIT_FILE_LINKED; +- return 1; + } + + return 0; + } + +-int unit_file_mask( +- UnitFileScope scope, +- bool runtime, +- const char *root_dir, +- char **files, +- bool force, +- UnitFileChange **changes, +- unsigned *n_changes) { +- +- char **i; +- _cleanup_free_ char *prefix = NULL; +- int r; ++static void install_info_free(InstallInfo *i) { + +- assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); ++ if (!i) ++ return; + +- r = get_config_path(scope, runtime, root_dir, &prefix); +- if (r < 0) +- return r; ++ free(i->name); ++ free(i->path); ++ strv_free(i->aliases); ++ strv_free(i->wanted_by); ++ strv_free(i->required_by); ++ strv_free(i->also); ++ free(i->default_instance); ++ free(i->symlink_target); ++ free(i); ++} + +- STRV_FOREACH(i, files) { +- _cleanup_free_ char *path = NULL; ++static OrderedHashmap* install_info_hashmap_free(OrderedHashmap *m) { ++ InstallInfo *i; + +- if (!unit_name_is_valid(*i, TEMPLATE_VALID)) { +- if (r == 0) +- r = -EINVAL; +- continue; +- } ++ while ((i = ordered_hashmap_steal_first(m))) ++ install_info_free(i); + +- path = path_make_absolute(*i, prefix); +- if (!path) { +- r = -ENOMEM; +- break; +- } ++ ordered_hashmap_free(m); + +- if (symlink("/dev/null", path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); +- continue; +- } ++ return NULL; ++} + +- if (errno == EEXIST) { ++static void install_context_done(InstallContext *c) { ++ assert(c); + +- if (null_or_empty_path(path) > 0) +- continue; ++ c->will_process = install_info_hashmap_free(c->will_process); ++ c->have_processed = install_info_hashmap_free(c->have_processed); ++} + +- if (force) { +- if (symlink_atomic("/dev/null", path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); +- continue; +- } +- } ++static InstallInfo *install_info_find(InstallContext *c, const char *name) { ++ InstallInfo *i; + +- if (r == 0) +- r = -EEXIST; +- } else { +- if (r == 0) +- r = -errno; +- } +- } ++ i = ordered_hashmap_get(c->have_processed, name); ++ if (i) ++ return i; + +- return r; +-} +- +-int unit_file_unmask( +- UnitFileScope scope, +- bool runtime, +- const char *root_dir, +- char **files, +- UnitFileChange **changes, +- unsigned *n_changes) { +- +- char **i, *config_path = NULL; +- int r, q; +- Set *remove_symlinks_to = NULL; +- +- assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); +- +- r = get_config_path(scope, runtime, root_dir, &config_path); +- if (r < 0) +- goto finish; +- +- STRV_FOREACH(i, files) { +- _cleanup_free_ char *path = NULL; +- +- if (!unit_name_is_valid(*i, TEMPLATE_VALID)) { +- if (r == 0) +- r = -EINVAL; +- continue; +- } +- +- path = path_make_absolute(*i, config_path); +- if (!path) { +- r = -ENOMEM; +- break; +- } +- +- q = null_or_empty_path(path); +- if (q > 0) { +- if (unlink(path) < 0) +- q = -errno; +- else { +- q = mark_symlink_for_removal(&remove_symlinks_to, path); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); +- } +- } +- +- if (q != -ENOENT && r == 0) +- r = q; +- } +- +- +-finish: +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); +- if (r == 0) +- r = q; +- +- set_free_free(remove_symlinks_to); +- free(config_path); +- +- return r; +-} +- +-int unit_file_link( +- UnitFileScope scope, +- bool runtime, +- const char *root_dir, +- char **files, +- bool force, +- UnitFileChange **changes, +- unsigned *n_changes) { +- +- _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- char **i; +- _cleanup_free_ char *config_path = NULL; +- int r, q; +- +- assert(scope >= 0); +- assert(scope < _UNIT_FILE_SCOPE_MAX); +- +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); +- if (r < 0) +- return r; +- +- r = get_config_path(scope, runtime, root_dir, &config_path); +- if (r < 0) +- return r; +- +- STRV_FOREACH(i, files) { +- _cleanup_free_ char *path = NULL; +- char *fn; +- struct stat st; +- +- fn = basename(*i); +- +- if (!path_is_absolute(*i) || +- !unit_name_is_valid(fn, TEMPLATE_VALID)) { +- if (r == 0) +- r = -EINVAL; +- continue; +- } +- +- if (lstat(*i, &st) < 0) { +- if (r == 0) +- r = -errno; +- continue; +- } +- +- if (!S_ISREG(st.st_mode)) { +- r = -ENOENT; +- continue; +- } +- +- q = in_search_path(*i, paths.unit_path); +- if (q < 0) +- return q; +- +- if (q > 0) +- continue; +- +- path = path_make_absolute(fn, config_path); +- if (!path) +- return -ENOMEM; +- +- if (symlink(*i, path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); +- continue; +- } +- +- if (errno == EEXIST) { +- _cleanup_free_ char *dest = NULL; +- +- q = readlink_and_make_absolute(path, &dest); +- if (q < 0 && errno != ENOENT) { +- if (r == 0) +- r = q; +- continue; +- } +- +- if (q >= 0 && path_equal(dest, *i)) +- continue; +- +- if (force) { +- if (symlink_atomic(*i, path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); +- continue; +- } +- } +- +- if (r == 0) +- r = -EEXIST; +- } else { +- if (r == 0) +- r = -errno; +- } +- } +- +- return r; +-} +- +-void unit_file_list_free(Hashmap *h) { +- UnitFileList *i; +- +- while ((i = hashmap_steal_first(h))) { +- free(i->path); +- free(i); +- } +- +- hashmap_free(h); +-} +- +-int unit_file_changes_add( +- UnitFileChange **changes, +- unsigned *n_changes, +- UnitFileChangeType type, +- const char *path, +- const char *source) { +- +- UnitFileChange *c; +- unsigned i; +- +- assert(path); +- assert(!changes == !n_changes); +- +- if (!changes) +- return 0; +- +- c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); +- if (!c) +- return -ENOMEM; +- +- *changes = c; +- i = *n_changes; +- +- c[i].type = type; +- c[i].path = strdup(path); +- if (!c[i].path) +- return -ENOMEM; +- +- path_kill_slashes(c[i].path); +- +- if (source) { +- c[i].source = strdup(source); +- if (!c[i].source) { +- free(c[i].path); +- return -ENOMEM; +- } +- +- path_kill_slashes(c[i].path); +- } else +- c[i].source = NULL; +- +- *n_changes = i+1; +- return 0; +-} +- +-void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { +- unsigned i; +- +- assert(changes || n_changes == 0); +- +- if (!changes) +- return; +- +- for (i = 0; i < n_changes; i++) { +- free(changes[i].path); +- free(changes[i].source); +- } +- +- free(changes); +-} +- +-static void install_info_free(InstallInfo *i) { +- assert(i); +- +- free(i->name); +- free(i->path); +- strv_free(i->aliases); +- strv_free(i->wanted_by); +- strv_free(i->required_by); +- strv_free(i->also); +- free(i->default_instance); +- free(i); +-} +- +-static void install_info_hashmap_free(OrderedHashmap *m) { +- InstallInfo *i; +- +- if (!m) +- return; +- +- while ((i = ordered_hashmap_steal_first(m))) +- install_info_free(i); +- +- ordered_hashmap_free(m); +-} +- +-static void install_context_done(InstallContext *c) { +- assert(c); +- +- install_info_hashmap_free(c->will_install); +- install_info_hashmap_free(c->have_installed); +- +- c->will_install = c->have_installed = NULL; ++ return ordered_hashmap_get(c->will_process, name); + } + + static int install_info_add( + InstallContext *c, + const char *name, +- const char *path) { ++ const char *path, ++ InstallInfo **ret) { ++ + InstallInfo *i = NULL; + int r; + +@@ -857,20 +768,24 @@ static int install_info_add( + if (!name) + name = basename(path); + +- if (!unit_name_is_valid(name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- if (ordered_hashmap_get(c->have_installed, name) || +- ordered_hashmap_get(c->will_install, name)) ++ i = install_info_find(c, name); ++ if (i) { ++ if (ret) ++ *ret = i; + return 0; ++ } + +- r = ordered_hashmap_ensure_allocated(&c->will_install, &string_hash_ops); ++ r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops); + if (r < 0) + return r; + + i = new0(InstallInfo, 1); + if (!i) + return -ENOMEM; ++ i->type = _UNIT_FILE_TYPE_INVALID; + + i->name = strdup(name); + if (!i->name) { +@@ -886,10 +801,13 @@ static int install_info_add( + } + } + +- r = ordered_hashmap_put(c->will_install, i->name, i); ++ r = ordered_hashmap_put(c->will_process, i->name, i); + if (r < 0) + goto fail; + ++ if (ret) ++ *ret = i; ++ + return 0; + + fail: +@@ -901,15 +819,16 @@ fail: + + static int install_info_add_auto( + InstallContext *c, +- const char *name_or_path) { ++ const char *name_or_path, ++ InstallInfo **ret) { + + assert(c); + assert(name_or_path); + + if (path_is_absolute(name_or_path)) +- return install_info_add(c, NULL, name_or_path); ++ return install_info_add(c, NULL, name_or_path, ret); + else +- return install_info_add(c, name_or_path, NULL); ++ return install_info_add(c, name_or_path, NULL, ret); + } + + static int config_parse_also( +@@ -928,6 +847,7 @@ static int config_parse_also( + const char *word, *state; + InstallContext *c = data; + InstallInfo *i = userdata; ++ int r; + + assert(filename); + assert(lvalue); +@@ -935,19 +855,20 @@ static int config_parse_also( + + FOREACH_WORD_QUOTED(word, l, rvalue, state) { + _cleanup_free_ char *n; +- int r; + + n = strndup(word, l); + if (!n) + return -ENOMEM; + +- r = install_info_add(c, n, NULL); ++ r = install_info_add(c, n, NULL, NULL); + if (r < 0) + return r; + +- r = strv_extend(&i->also, n); ++ r = strv_push(&i->also, n); + if (r < 0) + return r; ++ ++ n = NULL; + } + if (!isempty(state)) + log_syntax(unit, LOG_ERR, filename, line, EINVAL, +@@ -1026,9 +947,7 @@ static int unit_file_load( + InstallInfo *info, + const char *path, + const char *root_dir, +- bool allow_symlink, +- bool load, +- bool *also) { ++ SearchFlags flags) { + + const ConfigTableItem items[] = { + { "Install", "Alias", config_parse_strv, 0, &info->aliases }, +@@ -1041,7 +960,9 @@ static int unit_file_load( + }; + + _cleanup_fclose_ FILE *f = NULL; +- int fd, r; ++ _cleanup_close_ int fd = -1; ++ struct stat st; ++ int r; + + assert(c); + assert(info); +@@ -1050,20 +971,43 @@ static int unit_file_load( + if (!isempty(root_dir)) + path = strjoina(root_dir, "/", path); + +- if (!load) { +- r = access(path, F_OK) ? -errno : 0; +- return r; ++ if (!(flags & SEARCH_LOAD)) { ++ r = lstat(path, &st); ++ if (r < 0) ++ return -errno; ++ ++ if (null_or_empty(&st)) ++ info->type = UNIT_FILE_TYPE_MASKED; ++ else if (S_ISREG(st.st_mode)) ++ info->type = UNIT_FILE_TYPE_REGULAR; ++ else if (S_ISLNK(st.st_mode)) ++ return -ELOOP; ++ else if (S_ISDIR(st.st_mode)) ++ return -EISDIR; ++ else ++ return -ENOTTY; ++ ++ return 0; + } + +- fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW)); ++ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; ++ if (fstat(fd, &st) < 0) ++ return -errno; ++ if (null_or_empty(&st)) { ++ info->type = UNIT_FILE_MASKED; ++ return 0; ++ } ++ if (S_ISDIR(st.st_mode)) ++ return -EISDIR; ++ if (!S_ISREG(st.st_mode)) ++ return -ENOTTY; + + f = fdopen(fd, "re"); +- if (!f) { +- safe_close(fd); +- return -ENOMEM; +- } ++ if (!f) ++ return -errno; ++ fd = -1; + + r = config_parse(NULL, path, f, + NULL, +@@ -1072,8 +1016,7 @@ static int unit_file_load( + if (r < 0) + return r; + +- if (also) +- *also = !strv_isempty(info->also); ++ info->type = UNIT_FILE_TYPE_REGULAR; + + return + (int) strv_length(info->aliases) + +@@ -1081,14 +1024,73 @@ static int unit_file_load( + (int) strv_length(info->required_by); + } + ++static int unit_file_load_or_readlink( ++ InstallContext *c, ++ InstallInfo *info, ++ const char *path, ++ const char *root_dir, ++ SearchFlags flags) { ++ ++ _cleanup_free_ char *np = NULL; ++ int r; ++ ++ r = unit_file_load(c, info, path, root_dir, flags); ++ if (r != -ELOOP) ++ return r; ++ ++ /* This is a symlink, let's read it. */ ++ ++ r = readlink_and_make_absolute_root(root_dir, path, &np); ++ if (r < 0) ++ return r; ++ ++ if (path_equal(np, "/dev/null")) ++ info->type = UNIT_FILE_TYPE_MASKED; ++ else { ++ const char *bn; ++ UnitType a, b; ++ ++ bn = basename(np); ++ ++ if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) { ++ ++ if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN)) ++ return -EINVAL; ++ ++ } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { ++ ++ if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) ++ return -EINVAL; ++ ++ } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) { ++ ++ if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) ++ return -EINVAL; ++ } else ++ return -EINVAL; ++ ++ /* Enforce that the symlink destination does not ++ * change the unit file type. */ ++ ++ a = unit_name_to_type(info->name); ++ b = unit_name_to_type(bn); ++ if (a < 0 || b < 0 || a != b) ++ return -EINVAL; ++ ++ info->type = UNIT_FILE_TYPE_SYMLINK; ++ info->symlink_target = np; ++ np = NULL; ++ } ++ ++ return 0; ++} ++ + static int unit_file_search( + InstallContext *c, + InstallInfo *info, + const LookupPaths *paths, + const char *root_dir, +- bool allow_symlink, +- bool load, +- bool *also) { ++ SearchFlags flags) { + + char **p; + int r; +@@ -1097,8 +1099,12 @@ static int unit_file_search( + assert(info); + assert(paths); + ++ /* Was this unit already loaded? */ ++ if (info->type != _UNIT_FILE_TYPE_INVALID) ++ return 0; ++ + if (info->path) +- return unit_file_load(c, info, info->path, root_dir, allow_symlink, load, also); ++ return unit_file_load_or_readlink(c, info, info->path, root_dir, flags); + + assert(info->name); + +@@ -1109,14 +1115,15 @@ static int unit_file_search( + if (!path) + return -ENOMEM; + +- r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also); +- if (r >= 0) { ++ r = unit_file_load_or_readlink(c, info, path, root_dir, flags); ++ if (r < 0) { ++ if (r != -ENOENT) ++ return r; ++ } else { + info->path = path; + path = NULL; + return r; + } +- if (r != -ENOENT && r != -ELOOP) +- return r; + } + + if (unit_name_is_instance(info->name)) { +@@ -1138,92 +1145,149 @@ static int unit_file_search( + if (!path) + return -ENOMEM; + +- r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also); +- if (r >= 0) { ++ r = unit_file_load_or_readlink(c, info, path, root_dir, flags); ++ if (r < 0) { ++ if (r != -ENOENT) ++ return r; ++ } else { + info->path = path; + path = NULL; + return r; + } +- if (r != -ENOENT && r != -ELOOP) +- return r; + } + } + + return -ENOENT; + } + +-static int unit_file_can_install( +- const LookupPaths *paths, ++static int install_info_follow( ++ InstallContext *c, ++ InstallInfo *i, + const char *root_dir, +- const char *name, +- bool allow_symlink, +- bool *also) { ++ SearchFlags flags) { ++ ++ assert(c); ++ assert(i); ++ ++ if (i->type != UNIT_FILE_TYPE_SYMLINK) ++ return -EINVAL; ++ if (!i->symlink_target) ++ return -EINVAL; ++ ++ /* If the basename doesn't match, the caller should add a ++ * complete new entry for this. */ ++ ++ if (!streq(basename(i->symlink_target), i->name)) ++ return -EXDEV; ++ ++ free(i->path); ++ i->path = i->symlink_target; ++ i->symlink_target = NULL; ++ i->type = _UNIT_FILE_TYPE_INVALID; ++ ++ return unit_file_load_or_readlink(c, i, i->path, root_dir, flags); ++} ++ ++static int install_info_traverse( ++ UnitFileScope scope, ++ InstallContext *c, ++ const char *root_dir, ++ const LookupPaths *paths, ++ InstallInfo *start, ++ SearchFlags flags, ++ InstallInfo **ret) { + +- _cleanup_(install_context_done) InstallContext c = {}; + InstallInfo *i; ++ unsigned k = 0; + int r; + + assert(paths); +- assert(name); ++ assert(start); ++ assert(c); + +- r = install_info_add_auto(&c, name); ++ r = unit_file_search(c, start, paths, root_dir, flags); + if (r < 0) + return r; + +- assert_se(i = ordered_hashmap_first(c.will_install)); ++ i = start; ++ while (i->type == UNIT_FILE_TYPE_SYMLINK) { ++ /* Follow the symlink */ + +- r = unit_file_search(&c, i, paths, root_dir, allow_symlink, true, also); ++ if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX) ++ return -ELOOP; + +- if (r >= 0) +- r = +- (int) strv_length(i->aliases) + +- (int) strv_length(i->wanted_by) + +- (int) strv_length(i->required_by); ++ if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS) && is_config_path(scope, i->path)) ++ return -ELOOP; + +- return r; +-} ++ r = install_info_follow(c, i, root_dir, flags); ++ if (r < 0) { ++ _cleanup_free_ char *buffer = NULL; ++ const char *bn; + +-static int create_symlink( +- const char *old_path, +- const char *new_path, +- bool force, +- UnitFileChange **changes, +- unsigned *n_changes) { ++ if (r != -EXDEV) ++ return r; + +- _cleanup_free_ char *dest = NULL; +- int r; ++ /* Target has a different name, create a new ++ * install info object for that, and continue ++ * with that. */ + +- assert(old_path); +- assert(new_path); ++ bn = basename(i->symlink_target); + +- mkdir_parents_label(new_path, 0755); ++ if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) && ++ unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) { + +- if (symlink(old_path, new_path) >= 0) { +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); +- return 0; ++ _cleanup_free_ char *instance = NULL; ++ ++ r = unit_name_to_instance(i->name, &instance); ++ if (r < 0) ++ return r; ++ ++ buffer = unit_name_replace_instance(bn, instance); ++ if (!buffer) ++ return -ENOMEM; ++ ++ bn = buffer; ++ } ++ ++ r = install_info_add(c, bn, NULL, &i); ++ if (r < 0) ++ return r; ++ ++ r = unit_file_search(c, i, paths, root_dir, flags); ++ if (r < 0) ++ return r; ++ } ++ ++ /* Try again, with the new target we found. */ + } + +- if (errno != EEXIST) +- return -errno; ++ if (ret) ++ *ret = i; + +- r = readlink_and_make_absolute(new_path, &dest); +- if (r < 0) +- return r; ++ return 0; ++} ++ ++static int install_info_discover( ++ UnitFileScope scope, ++ InstallContext *c, ++ const char *root_dir, ++ const LookupPaths *paths, ++ const char *name, ++ SearchFlags flags, ++ InstallInfo **ret) { + +- if (path_equal(dest, old_path)) +- return 0; ++ InstallInfo *i; ++ int r; + +- if (!force) +- return -EEXIST; ++ assert(c); ++ assert(paths); ++ assert(name); + +- r = symlink_atomic(old_path, new_path); ++ r = install_info_add_auto(c, name, &i); + if (r < 0) + return r; + +- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); +- unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); +- +- return 0; ++ return install_info_traverse(scope, c, root_dir, paths, i, flags, ret); + } + + static int install_info_symlink_alias( +@@ -1298,7 +1362,7 @@ static int install_info_symlink_wants( + if (q < 0) + return q; + +- if (!unit_name_is_valid(dst, TEMPLATE_VALID)) { ++ if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) { + r = -EINVAL; + continue; + } +@@ -1358,6 +1422,9 @@ static int install_info_apply( + assert(paths); + assert(config_path); + ++ if (i->type != UNIT_FILE_TYPE_REGULAR) ++ return 0; ++ + r = install_info_symlink_alias(i, config_path, force, changes, n_changes); + + q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes); +@@ -1376,53 +1443,59 @@ static int install_info_apply( + } + + static int install_context_apply( ++ UnitFileScope scope, + InstallContext *c, + const LookupPaths *paths, + const char *config_path, + const char *root_dir, + bool force, ++ SearchFlags flags, + UnitFileChange **changes, + unsigned *n_changes) { + + InstallInfo *i; +- int r, q; ++ int r; + + assert(c); + assert(paths); + assert(config_path); + +- if (!ordered_hashmap_isempty(c->will_install)) { +- r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops); +- if (r < 0) +- return r; ++ if (ordered_hashmap_isempty(c->will_process)) ++ return 0; + +- r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install)); +- if (r < 0) +- return r; +- } ++ r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); ++ if (r < 0) ++ return r; + + r = 0; +- while ((i = ordered_hashmap_first(c->will_install))) { +- assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); ++ while ((i = ordered_hashmap_first(c->will_process))) { ++ int q; + +- q = unit_file_search(c, i, paths, root_dir, false, true, NULL); +- if (q < 0) { +- if (r >= 0) +- r = q; ++ q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); ++ if (q < 0) ++ return q; + ++ r = install_info_traverse(scope, c, root_dir, paths, i, flags, NULL); ++ if (r < 0) + return r; +- } else if (r >= 0) +- r += q; ++ ++ if (i->type != UNIT_FILE_TYPE_REGULAR) ++ continue; + + q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes); +- if (r >= 0 && q < 0) +- r = q; ++ if (r >= 0) { ++ if (q < 0) ++ r = q; ++ else ++ r+= q; ++ } + } + + return r; + } + + static int install_context_mark_for_removal( ++ UnitFileScope scope, + InstallContext *c, + const LookupPaths *paths, + Set **remove_symlinks_to, +@@ -1430,96 +1503,109 @@ static int install_context_mark_for_removal( + const char *root_dir) { + + InstallInfo *i; +- int r, q; ++ int r; + + assert(c); + assert(paths); + assert(config_path); + + /* Marks all items for removal */ +- +- if (!ordered_hashmap_isempty(c->will_install)) { +- r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops); ++ if (!ordered_hashmap_isempty(c->will_process)) { ++ r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); + if (r < 0) + return r; + +- r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install)); ++ r = ordered_hashmap_reserve(c->have_processed, ordered_hashmap_size(c->will_process)); + if (r < 0) + return r; + } + + r = 0; +- while ((i = ordered_hashmap_first(c->will_install))) { +- assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); +- +- q = unit_file_search(c, i, paths, root_dir, false, true, NULL); +- if (q == -ENOENT) { +- /* do nothing */ +- } else if (q < 0) { +- if (r >= 0) +- r = q; ++ while ((i = ordered_hashmap_first(c->will_process))) { ++ ++ r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); ++ if (r < 0) ++ return r; + ++ r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); ++ if (r < 0) + return r; +- } else if (r >= 0) +- r += q; +- +- if (unit_name_is_instance(i->name)) { +- char *unit_file; +- +- if (i->path) { +- unit_file = basename(i->path); +- +- if (unit_name_is_instance(unit_file)) +- /* unit file named as instance exists, thus all symlinks +- * pointing to it will be removed */ +- q = mark_symlink_for_removal(remove_symlinks_to, i->name); +- else +- /* does not exist, thus we will mark for removal symlinks +- * to template unit file */ +- q = mark_symlink_for_removal(remove_symlinks_to, unit_file); +- } else { +- /* If i->path is not set, it means that we didn't actually find +- * the unit file. But we can still remove symlinks to the +- * nonexistent template. */ +- unit_file = unit_name_template(i->name); +- if (!unit_file) +- return log_oom(); +- +- q = mark_symlink_for_removal(remove_symlinks_to, unit_file); +- free(unit_file); +- } +- } else +- q = mark_symlink_for_removal(remove_symlinks_to, i->name); + +- if (r >= 0 && q < 0) ++ if (i->type != UNIT_FILE_TYPE_REGULAR) ++ continue; ++ ++ r = mark_symlink_for_removal(remove_symlinks_to, i->name); ++ if (r < 0) ++ return r; ++ } ++ ++ return 0; ++} ++ ++int unit_file_mask( ++ UnitFileScope scope, ++ bool runtime, ++ const char *root_dir, ++ char **files, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { ++ ++ _cleanup_free_ char *prefix = NULL; ++ char **i; ++ int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ ++ r = get_config_path(scope, runtime, root_dir, &prefix); ++ if (r < 0) ++ return r; ++ ++ STRV_FOREACH(i, files) { ++ _cleanup_free_ char *path = NULL; ++ int q; ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) { ++ if (r == 0) ++ r = -EINVAL; ++ continue; ++ } ++ ++ path = path_make_absolute(*i, prefix); ++ if (!path) ++ return -ENOMEM; ++ ++ q = create_symlink("/dev/null", path, force, changes, n_changes); ++ if (q < 0 && r >= 0) + r = q; + } + + return r; + } + +-int unit_file_add_dependency( ++int unit_file_unmask( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, +- char *target, +- UnitDependency dep, +- bool force, + UnitFileChange **changes, + unsigned *n_changes) { + +- _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- _cleanup_(install_context_done) InstallContext c = {}; ++ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + _cleanup_free_ char *config_path = NULL; ++ _cleanup_free_ char **todo = NULL; ++ size_t n_todo = 0, n_allocated = 0; + char **i; +- int r; +- InstallInfo *info; ++ int r, q; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + +@@ -1528,57 +1614,222 @@ int unit_file_add_dependency( + return r; + + STRV_FOREACH(i, files) { +- UnitFileState state; ++ _cleanup_free_ char *path = NULL; + +- state = unit_file_get_state(scope, root_dir, *i); +- if (state < 0) +- return log_error_errno(state, "Failed to get unit file state for %s: %m", *i); ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) ++ return -EINVAL; + +- if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) { +- log_error("Failed to enable unit: Unit %s is masked", *i); +- return -ENOTSUP; +- } ++ path = path_make_absolute(*i, config_path); ++ if (!path) ++ return -ENOMEM; + +- r = install_info_add_auto(&c, *i); ++ r = null_or_empty_path(path); ++ if (r == -ENOENT) ++ continue; + if (r < 0) + return r; ++ if (r == 0) ++ continue; ++ ++ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) ++ return -ENOMEM; ++ ++ todo[n_todo++] = *i; + } + +- if (!ordered_hashmap_isempty(c.will_install)) { +- r = ordered_hashmap_ensure_allocated(&c.have_installed, &string_hash_ops); +- if (r < 0) +- return r; ++ strv_uniq(todo); + +- r = ordered_hashmap_reserve(c.have_installed, ordered_hashmap_size(c.will_install)); +- if (r < 0) +- return r; ++ r = 0; ++ STRV_FOREACH(i, todo) { ++ _cleanup_free_ char *path = NULL; ++ ++ path = path_make_absolute(*i, config_path); ++ if (!path) ++ return -ENOMEM; ++ ++ if (unlink(path) < 0) { ++ if (errno != -ENOENT && r >= 0) ++ r = -errno; ++ } else { ++ q = mark_symlink_for_removal(&remove_symlinks_to, path); ++ if (q < 0) ++ return q; ++ ++ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); ++ } + } + +- while ((info = ordered_hashmap_first(c.will_install))) { +- assert_se(ordered_hashmap_move_one(c.have_installed, c.will_install, info->name) == 0); ++ q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); ++ if (r >= 0) ++ r = q; + +- r = unit_file_search(&c, info, &paths, root_dir, false, false, NULL); +- if (r < 0) +- return r; ++ return r; ++} + +- if (dep == UNIT_WANTS) +- r = strv_extend(&info->wanted_by, target); +- else if (dep == UNIT_REQUIRES) +- r = strv_extend(&info->required_by, target); +- else +- r = -EINVAL; ++int unit_file_link( ++ UnitFileScope scope, ++ bool runtime, ++ const char *root_dir, ++ char **files, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { + +- if (r < 0) +- return r; ++ _cleanup_lookup_paths_free_ LookupPaths paths = {}; ++ _cleanup_free_ char *config_path = NULL; ++ _cleanup_free_ char **todo = NULL; ++ size_t n_todo = 0, n_allocated = 0; ++ char **i; ++ int r,q; + +- r = install_info_apply(info, &paths, config_path, root_dir, force, changes, n_changes); +- if (r < 0) +- return r; ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ if (r < 0) ++ return r; ++ ++ r = get_config_path(scope, runtime, root_dir, &config_path); ++ if (r < 0) ++ return r; ++ ++ STRV_FOREACH(i, files) { ++ _cleanup_free_ char *full = NULL; ++ struct stat st; ++ char *fn; ++ ++ if (!path_is_absolute(*i)) ++ return -EINVAL; ++ ++ fn = basename(*i); ++ if (!unit_name_is_valid(fn, UNIT_NAME_ANY)) ++ return -EINVAL; ++ ++ full = prefix_root(root_dir, *i); ++ if (!full) ++ return -ENOMEM; ++ ++ if (lstat(full, &st) < 0) ++ return -errno; ++ if (S_ISLNK(st.st_mode)) ++ return -ELOOP; ++ if (S_ISDIR(st.st_mode)) ++ return -EISDIR; ++ if (!S_ISREG(st.st_mode)) ++ return -ENOTTY; ++ ++ q = in_search_path(*i, paths.unit_path); ++ if (q < 0) ++ return q; ++ if (q > 0) ++ continue; ++ ++ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) ++ return -ENOMEM; ++ ++ todo[n_todo++] = *i; + } + +- return 0; ++ strv_uniq(todo); ++ ++ r = 0; ++ STRV_FOREACH(i, todo) { ++ _cleanup_free_ char *path = NULL; ++ ++ path = path_make_absolute(basename(*i), config_path); ++ if (!path) ++ return -ENOMEM; ++ ++ q = create_symlink(*i, path, force, changes, n_changes); ++ if (q < 0 && r >= 0) ++ r = q; ++ } ++ ++ return r; ++} ++ ++int unit_file_add_dependency( ++ UnitFileScope scope, ++ bool runtime, ++ const char *root_dir, ++ char **files, ++ const char *target, ++ UnitDependency dep, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { ++ ++ _cleanup_lookup_paths_free_ LookupPaths paths = {}; ++ _cleanup_(install_context_done) InstallContext c = {}; ++ _cleanup_free_ char *config_path = NULL; ++ InstallInfo *i, *target_info; ++ char **f; ++ int r; ++ ++ assert(scope >= 0); ++ assert(scope < _UNIT_FILE_SCOPE_MAX); ++ assert(target); ++ ++ if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES)) ++ return -EINVAL; ++ ++ if (!unit_name_is_valid(target, UNIT_NAME_ANY)) ++ return -EINVAL; ++ ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ if (r < 0) ++ return r; ++ ++ r = get_config_path(scope, runtime, root_dir, &config_path); ++ if (r < 0) ++ return r; ++ ++ r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info); ++ if (r < 0) ++ return r; ++ if (target_info->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; ++ ++ assert(target_info->type == UNIT_FILE_TYPE_REGULAR); ++ ++ STRV_FOREACH(f, files) { ++ char ***l; ++ ++ r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; ++ ++ assert(i->type == UNIT_FILE_TYPE_REGULAR); ++ ++ /* We didn't actually load anything from the unit ++ * file, but instead just add in our new symlink to ++ * create. */ ++ ++ if (dep == UNIT_WANTS) ++ l = &i->wanted_by; ++ else ++ l = &i->required_by; ++ ++ strv_free(*l); ++ *l = strv_new(target_info->name, NULL); ++ if (!*l) ++ return -ENOMEM; ++ } ++ ++ return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + } + ++ + int unit_file_enable( + UnitFileScope scope, + bool runtime, +@@ -1590,13 +1841,18 @@ int unit_file_enable( + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(install_context_done) InstallContext c = {}; +- char **i; + _cleanup_free_ char *config_path = NULL; ++ InstallInfo *i; ++ char **f; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +@@ -1605,21 +1861,14 @@ int unit_file_enable( + if (r < 0) + return r; + +- STRV_FOREACH(i, files) { +- UnitFileState state; +- +- /* We only want to know if this unit is masked, so we ignore +- * errors from unit_file_get_state, deferring other checks. +- * This allows templated units to be enabled on the fly. */ +- state = unit_file_get_state(scope, root_dir, *i); +- if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) { +- log_error("Failed to enable unit: Unit %s is masked", *i); +- return -ENOTSUP; +- } +- +- r = install_info_add_auto(&c, *i); ++ STRV_FOREACH(f, files) { ++ r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i); + if (r < 0) + return r; ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; ++ ++ assert(i->type == UNIT_FILE_TYPE_REGULAR); + } + + /* This will return the number of symlink rules that were +@@ -1627,7 +1876,7 @@ int unit_file_enable( + useful to determine whether the passed files had any + installation data at all. */ + +- return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); ++ return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); + } + + int unit_file_disable( +@@ -1640,14 +1889,18 @@ int unit_file_disable( + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(install_context_done) InstallContext c = {}; +- char **i; + _cleanup_free_ char *config_path = NULL; + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +- int r, q; ++ char **i; ++ int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +@@ -1657,18 +1910,19 @@ int unit_file_disable( + return r; + + STRV_FOREACH(i, files) { +- r = install_info_add_auto(&c, *i); ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) ++ return -EINVAL; ++ ++ r = install_info_add(&c, *i, NULL, NULL); + if (r < 0) + return r; + } + +- r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir); +- +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); +- if (r >= 0) +- r = q; ++ r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, root_dir); ++ if (r < 0) ++ return r; + +- return r; ++ return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + } + + int unit_file_reenable( +@@ -1679,21 +1933,30 @@ int unit_file_reenable( + bool force, + UnitFileChange **changes, + unsigned *n_changes) { ++ ++ char **n; + int r; ++ size_t l, i; ++ ++ /* First, we invoke the disable command with only the basename... */ ++ l = strv_length(files); ++ n = newa(char*, l+1); ++ for (i = 0; i < l; i++) ++ n[i] = basename(files[i]); ++ n[i] = NULL; + +- r = unit_file_disable(scope, runtime, root_dir, files, +- changes, n_changes); ++ r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes); + if (r < 0) + return r; + +- return unit_file_enable(scope, runtime, root_dir, files, force, +- changes, n_changes); ++ /* But the enable command with the full name */ ++ return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes); + } + + int unit_file_set_default( + UnitFileScope scope, + const char *root_dir, +- const char *file, ++ const char *name, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { +@@ -1701,42 +1964,40 @@ int unit_file_set_default( + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(install_context_done) InstallContext c = {}; + _cleanup_free_ char *config_path = NULL; +- char *path; ++ InstallInfo *i; ++ const char *path; + int r; +- InstallInfo *i = NULL; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); +- assert(file); ++ assert(name); + +- if (unit_name_to_type(file) != UNIT_TARGET) ++ if (unit_name_to_type(name) != UNIT_TARGET) ++ return -EINVAL; ++ if (streq(name, SPECIAL_DEFAULT_TARGET)) + return -EINVAL; + +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + +- r = get_config_path(scope, false, root_dir, &config_path); ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; + +- r = install_info_add_auto(&c, file); ++ r = get_config_path(scope, false, root_dir, &config_path); + if (r < 0) + return r; + +- assert_se(i = ordered_hashmap_first(c.will_install)); +- +- r = unit_file_search(&c, i, &paths, root_dir, false, true, NULL); ++ r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i); + if (r < 0) + return r; ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; + + path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET); + +- r = create_symlink(i->path, path, force, changes, n_changes); +- if (r < 0) +- return r; +- +- return 0; ++ return create_symlink(i->path, path, force, changes, n_changes); + } + + int unit_file_get_default( +@@ -1745,127 +2006,100 @@ int unit_file_get_default( + char **name) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; +- char **p; ++ _cleanup_(install_context_done) InstallContext c = {}; ++ InstallInfo *i; ++ char *n; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + +- STRV_FOREACH(p, paths.unit_path) { +- _cleanup_free_ char *path = NULL, *tmp = NULL; +- char *n; +- +- path = path_join(root_dir, *p, SPECIAL_DEFAULT_TARGET); +- if (!path) +- return -ENOMEM; +- +- r = readlink_malloc(path, &tmp); +- if (r == -ENOENT) +- continue; +- else if (r == -EINVAL) +- /* not a symlink */ +- n = strdup(SPECIAL_DEFAULT_TARGET); +- else if (r < 0) +- return r; +- else +- n = strdup(basename(tmp)); ++ r = lookup_paths_init_from_scope(&paths, scope, root_dir); ++ if (r < 0) ++ return r; + +- if (!n) +- return -ENOMEM; ++ r = install_info_discover(scope, &c, root_dir, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; + +- *name = n; +- return 0; +- } ++ n = strdup(i->name); ++ if (!n) ++ return -ENOMEM; + +- return -ENOENT; ++ *name = n; ++ return 0; + } + + UnitFileState unit_file_lookup_state( + UnitFileScope scope, + const char *root_dir, + const LookupPaths *paths, +- const char *name) { +- +- UnitFileState state = _UNIT_FILE_STATE_INVALID; +- char **i; +- _cleanup_free_ char *path = NULL; ++ const char *name, ++ UnitFileState *ret) { ++ _cleanup_(install_context_done) InstallContext c = {}; ++ InstallInfo *i; ++ UnitFileState state; + int r; + + assert(paths); ++ assert(name); + +- if (!unit_name_is_valid(name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + +- STRV_FOREACH(i, paths->unit_path) { +- struct stat st; +- char *partial; +- bool also = false; +- +- free(path); +- path = path_join(root_dir, *i, name); +- if (!path) +- return -ENOMEM; ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; + +- if (root_dir) +- partial = path + strlen(root_dir); +- else +- partial = path; ++ r = install_info_discover(scope, &c, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; + +- /* +- * Search for a unit file in our default paths, to +- * be sure, that there are no broken symlinks. +- */ +- if (lstat(path, &st) < 0) { +- r = -errno; +- if (errno != ENOENT) +- return r; ++ /* Shortcut things, if the caller just wants to know if this unit exists. */ ++ if (!ret) ++ return 0; + +- if (!unit_name_is_instance(name)) +- continue; +- } else { +- if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) +- return -ENOENT; ++ switch (i->type) { + +- r = null_or_empty_path(path); +- if (r < 0 && r != -ENOENT) +- return r; +- else if (r > 0) { +- state = path_startswith(*i, "/run") ? +- UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; +- return state; +- } +- } ++ case UNIT_FILE_TYPE_MASKED: ++ state = path_startswith(i->path, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; ++ break; + +- r = find_symlinks_in_scope(scope, root_dir, name, &state); ++ case UNIT_FILE_TYPE_REGULAR: ++ r = find_symlinks_in_scope(scope, root_dir, i->name, &state); + if (r < 0) + return r; +- else if (r > 0) +- return state; +- +- r = unit_file_can_install(paths, root_dir, partial, true, &also); +- if (r < 0 && errno != ENOENT) +- return r; +- else if (r > 0) +- return UNIT_FILE_DISABLED; +- else if (r == 0) { +- if (also) +- return UNIT_FILE_INDIRECT; +- return UNIT_FILE_STATIC; ++ if (r == 0) { ++ if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i)) ++ state = UNIT_FILE_DISABLED; ++ else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i)) ++ state = UNIT_FILE_INDIRECT; ++ else ++ state = UNIT_FILE_STATIC; + } ++ ++ break; ++ ++ default: ++ assert_not_reached("Unexpect unit file type."); + } + +- return r < 0 ? r : state; ++ *ret = state; ++ return 0; + } + +-UnitFileState unit_file_get_state( ++int unit_file_get_state( + UnitFileScope scope, + const char *root_dir, +- const char *name) { ++ const char *name, ++ UnitFileState *ret) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + int r; +@@ -1874,14 +2108,15 @@ UnitFileState unit_file_get_state( + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + +- if (root_dir && scope != UNIT_FILE_SYSTEM) +- return -EINVAL; ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; + + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; + +- return unit_file_lookup_state(scope, root_dir, &paths, name); ++ return unit_file_lookup_state(scope, root_dir, &paths, name, ret); + } + + int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { +@@ -1893,6 +2128,13 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(name); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ ++ if (!unit_name_is_valid(name, UNIT_NAME_ANY)) ++ return -EINVAL; ++ + if (scope == UNIT_FILE_SYSTEM) + r = conf_files_list(&files, ".preset", root_dir, + "/etc/systemd/system-preset", +@@ -1909,13 +2151,14 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + "/usr/lib/systemd/user-preset", + NULL); + else +- return 1; ++ return 1; /* Default is "enable" */ + + if (r < 0) + return r; + + STRV_FOREACH(p, files) { + _cleanup_fclose_ FILE *f; ++ char line[LINE_MAX]; + + f = fopen(*p, "re"); + if (!f) { +@@ -1925,39 +2168,38 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + return -errno; + } + +- for (;;) { +- char line[LINE_MAX], *l; +- +- if (!fgets(line, sizeof(line), f)) +- break; ++ FOREACH_LINE(line, f, return -errno) { ++ const char *parameter; ++ char *l; + + l = strstrip(line); +- if (!*l) +- continue; + +- if (strchr(COMMENTS "\n", *l)) ++ if (isempty(l)) ++ continue; ++ if (strchr(COMMENTS, *l)) + continue; + +- if (first_word(l, "enable")) { +- l += 6; +- l += strspn(l, WHITESPACE); +- +- if (fnmatch(l, name, FNM_NOESCAPE) == 0) { ++ parameter = first_word(l, "enable"); ++ if (parameter) { ++ if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { + log_debug("Preset file says enable %s.", name); + return 1; + } + +- } else if (first_word(l, "disable")) { +- l += 7; +- l += strspn(l, WHITESPACE); ++ continue; ++ } + +- if (fnmatch(l, name, FNM_NOESCAPE) == 0) { ++ parameter = first_word(l, "disable"); ++ if (parameter) { ++ if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { + log_debug("Preset file says disable %s.", name); + return 0; + } + +- } else +- log_debug("Couldn't parse line '%s'", l); ++ continue; ++ } ++ ++ log_debug("Couldn't parse line '%s'", l); + } + } + +@@ -1966,6 +2208,86 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char + return 1; + } + ++static int execute_preset( ++ UnitFileScope scope, ++ InstallContext *plus, ++ InstallContext *minus, ++ const LookupPaths *paths, ++ const char *config_path, ++ const char *root_dir, ++ char **files, ++ UnitFilePresetMode mode, ++ bool force, ++ UnitFileChange **changes, ++ unsigned *n_changes) { ++ ++ int r; ++ ++ assert(plus); ++ assert(minus); ++ assert(paths); ++ assert(config_path); ++ ++ if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { ++ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; ++ ++ r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, root_dir); ++ if (r < 0) ++ return r; ++ ++ r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); ++ } else ++ r = 0; ++ ++ if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { ++ int q; ++ ++ /* Returns number of symlinks that where supposed to be installed. */ ++ q = install_context_apply(scope, plus, paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); ++ if (r >= 0) { ++ if (q < 0) ++ r = q; ++ else ++ r+= q; ++ } ++ } ++ ++ return r; ++} ++ ++static int preset_prepare_one( ++ UnitFileScope scope, ++ InstallContext *plus, ++ InstallContext *minus, ++ LookupPaths *paths, ++ const char *root_dir, ++ UnitFilePresetMode mode, ++ const char *name) { ++ ++ InstallInfo *i; ++ int r; ++ ++ if (install_info_find(plus, name) || ++ install_info_find(minus, name)) ++ return 0; ++ ++ r = unit_file_query_preset(scope, root_dir, name); ++ if (r < 0) ++ return r; ++ ++ if (r > 0) { ++ r = install_info_discover(scope, plus, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; ++ ++ if (i->type == UNIT_FILE_TYPE_MASKED) ++ return -ESHUTDOWN; ++ } else ++ r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ ++ return r; ++} ++ + int unit_file_preset( + UnitFileScope scope, + bool runtime, +@@ -1980,12 +2302,16 @@ int unit_file_preset( + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_free_ char *config_path = NULL; + char **i; +- int r, q; ++ int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(mode < _UNIT_FILE_PRESET_MAX); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +@@ -1995,44 +2321,15 @@ int unit_file_preset( + return r; + + STRV_FOREACH(i, files) { +- +- if (!unit_name_is_valid(*i, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + +- r = unit_file_query_preset(scope, root_dir, *i); +- if (r < 0) +- return r; +- +- if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY) +- r = install_info_add_auto(&plus, *i); +- else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY) +- r = install_info_add_auto(&minus, *i); +- else +- r = 0; ++ r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, *i); + if (r < 0) + return r; + } + +- r = 0; +- +- if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { +- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +- +- r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); +- +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); +- if (r == 0) +- r = q; +- } +- +- if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { +- /* Returns number of symlinks that where supposed to be installed. */ +- q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes); +- if (r == 0) +- r = q; +- } +- +- return r; ++ return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes); + } + + int unit_file_preset_all( +@@ -2048,12 +2345,16 @@ int unit_file_preset_all( + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_free_ char *config_path = NULL; + char **i; +- int r, q; ++ int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(mode < _UNIT_FILE_PRESET_MAX); + ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; ++ + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; +@@ -2092,48 +2393,21 @@ int unit_file_preset_all( + if (hidden_file(de->d_name)) + continue; + +- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) + continue; + + dirent_ensure_type(d, de); + +- if (de->d_type != DT_REG) ++ if (!IN_SET(de->d_type, DT_LNK, DT_REG)) + continue; + +- r = unit_file_query_preset(scope, root_dir, de->d_name); +- if (r < 0) +- return r; +- +- if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY) +- r = install_info_add_auto(&plus, de->d_name); +- else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY) +- r = install_info_add_auto(&minus, de->d_name); +- else +- r = 0; ++ r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name); + if (r < 0) + return r; + } + } + +- r = 0; +- +- if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { +- _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; +- +- r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); +- +- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, NULL); +- if (r == 0) +- r = q; +- } +- +- if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { +- q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes); +- if (r == 0) +- r = q; +- } +- +- return r; ++ return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes); + } + + static void unit_file_list_free_one(UnitFileList *f) { +@@ -2144,6 +2418,17 @@ static void unit_file_list_free_one(UnitFileList *f) { + free(f); + } + ++Hashmap* unit_file_list_free(Hashmap *h) { ++ UnitFileList *i; ++ ++ while ((i = hashmap_steal_first(h))) ++ unit_file_list_free_one(i); ++ ++ hashmap_free(h); ++ ++ return NULL; ++} ++ + DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one); + + int unit_file_get_list( +@@ -2159,14 +2444,9 @@ int unit_file_get_list( + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(h); + +- if (root_dir && scope != UNIT_FILE_SYSTEM) +- return -EINVAL; +- +- if (root_dir) { +- r = access(root_dir, F_OK); +- if (r < 0) +- return -errno; +- } ++ r = verify_root_dir(scope, &root_dir); ++ if (r < 0) ++ return r; + + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) +@@ -2191,7 +2471,6 @@ int unit_file_get_list( + for (;;) { + _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL; + struct dirent *de; +- _cleanup_free_ char *path = NULL; + + errno = 0; + de = readdir(d); +@@ -2204,7 +2483,7 @@ int unit_file_get_list( + if (hidden_file(de->d_name)) + continue; + +- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID)) ++ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) + continue; + + if (hashmap_get(h, de->d_name)) +@@ -2223,44 +2502,14 @@ int unit_file_get_list( + if (!f->path) + return -ENOMEM; + +- r = null_or_empty_path(f->path); +- if (r < 0 && r != -ENOENT) +- return r; +- else if (r > 0) { +- f->state = +- path_startswith(*i, "/run") ? +- UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; +- goto found; +- } +- +- r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state); ++ r = unit_file_lookup_state(scope, root_dir, &paths, basename(f->path), &f->state); + if (r < 0) +- return r; +- else if (r > 0) { +- f->state = UNIT_FILE_ENABLED; +- goto found; +- } +- +- path = path_make_absolute(de->d_name, *i); +- if (!path) +- return -ENOMEM; ++ f->state = UNIT_FILE_BAD; + +- r = unit_file_can_install(&paths, root_dir, path, true, NULL); +- if (r == -EINVAL || /* Invalid setting? */ +- r == -EBADMSG || /* Invalid format? */ +- r == -ENOENT /* Included file not found? */) +- f->state = UNIT_FILE_INVALID; +- else if (r < 0) +- return r; +- else if (r > 0) +- f->state = UNIT_FILE_DISABLED; +- else +- f->state = UNIT_FILE_STATIC; +- +- found: + r = hashmap_put(h, basename(f->path), f); + if (r < 0) + return r; ++ + f = NULL; /* prevent cleanup */ + } + } +@@ -2278,7 +2527,7 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { + [UNIT_FILE_STATIC] = "static", + [UNIT_FILE_DISABLED] = "disabled", + [UNIT_FILE_INDIRECT] = "indirect", +- [UNIT_FILE_INVALID] = "invalid", ++ [UNIT_FILE_BAD] = "bad", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); +diff --git a/src/shared/install.h b/src/shared/install.h +index d729e6e..87a40b6 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -24,6 +24,7 @@ + #include "hashmap.h" + #include "unit-name.h" + #include "path-lookup.h" ++#include "strv.h" + + typedef enum UnitFileScope { + UNIT_FILE_SYSTEM, +@@ -43,7 +44,7 @@ typedef enum UnitFileState { + UNIT_FILE_STATIC, + UNIT_FILE_DISABLED, + UNIT_FILE_INDIRECT, +- UNIT_FILE_INVALID, ++ UNIT_FILE_BAD, + _UNIT_FILE_STATE_MAX, + _UNIT_FILE_STATE_INVALID = -1 + } UnitFileState; +@@ -74,6 +75,14 @@ typedef struct UnitFileList { + UnitFileState state; + } UnitFileList; + ++typedef enum UnitFileType { ++ UNIT_FILE_TYPE_REGULAR, ++ UNIT_FILE_TYPE_SYMLINK, ++ UNIT_FILE_TYPE_MASKED, ++ _UNIT_FILE_TYPE_MAX, ++ _UNIT_FILE_TYPE_INVALID = -1, ++} UnitFileType; ++ + typedef struct { + char *name; + char *path; +@@ -85,8 +94,26 @@ typedef struct { + char **also; + + char *default_instance; ++ ++ UnitFileType type; ++ ++ char *symlink_target; + } InstallInfo; + ++static inline bool UNIT_FILE_INSTALL_INFO_HAS_RULES(InstallInfo *i) { ++ assert(i); ++ ++ return !strv_isempty(i->aliases) || ++ !strv_isempty(i->wanted_by) || ++ !strv_isempty(i->required_by); ++} ++ ++static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(InstallInfo *i) { ++ assert(i); ++ ++ return !strv_isempty(i->also); ++} ++ + int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); + int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); + int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); +@@ -97,21 +124,14 @@ int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char + int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); + int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes); + int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name); +-int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); +- +-UnitFileState unit_file_lookup_state( +- UnitFileScope scope, +- const char *root_dir, +- const LookupPaths *paths, +- const char *name); +-UnitFileState unit_file_get_state( +- UnitFileScope scope, +- const char *root_dir, +- const char *filename); ++int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); ++ ++int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret); ++int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); + + int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); ++Hashmap* unit_file_list_free(Hashmap *h); + +-void unit_file_list_free(Hashmap *h); + int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source); + void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes); + +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index d5510bf..1181ffb 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -704,3 +704,37 @@ int fsck_exists(const char *fstype) { + + return 0; + } ++ ++char *prefix_root(const char *root, const char *path) { ++ char *n, *p; ++ size_t l; ++ ++ /* If root is passed, prefixes path with it. Otherwise returns ++ * it as is. */ ++ ++ assert(path); ++ ++ /* First, drop duplicate prefixing slashes from the path */ ++ while (path[0] == '/' && path[1] == '/') ++ path++; ++ ++ if (isempty(root) || path_equal(root, "/")) ++ return strdup(path); ++ ++ l = strlen(root) + 1 + strlen(path) + 1; ++ ++ n = new(char, l); ++ if (!n) ++ return NULL; ++ ++ p = stpcpy(n, root); ++ ++ while (p > n && p[-1] == '/') ++ p--; ++ ++ if (path[0] != '/') ++ *(p++) = '/'; ++ ++ strcpy(p, path); ++ return n; ++} +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index ca81b49..71bb740 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -63,6 +63,33 @@ bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool + + int fsck_exists(const char *fstype); + ++char *prefix_root(const char *root, const char *path); ++ ++/* Similar to prefix_root(), but returns an alloca() buffer, or ++ * possibly a const pointer into the path parameter */ ++#define prefix_roota(root, path) \ ++ ({ \ ++ const char* _path = (path), *_root = (root), *_ret; \ ++ char *_p, *_n; \ ++ size_t _l; \ ++ while (_path[0] == '/' && _path[1] == '/') \ ++ _path ++; \ ++ if (isempty(_root) || path_equal(_root, "/")) \ ++ _ret = _path; \ ++ else { \ ++ _l = strlen(_root) + 1 + strlen(_path) + 1; \ ++ _n = alloca(_l); \ ++ _p = stpcpy(_n, _root); \ ++ while (_p > _n && _p[-1] == '/') \ ++ _p--; \ ++ if (_path[0] != '/') \ ++ *(_p++) = '/'; \ ++ strcpy(_p, _path); \ ++ _ret = _n; \ ++ } \ ++ _ret; \ ++ }) ++ + /* Iterates through the path prefixes of the specified path, going up + * the tree, to root. Also returns "" (and not "/"!) for the root + * directory. Excludes the specified directory itself */ +diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c +index f728af4..b7827d1 100644 +--- a/src/shared/unit-name.c ++++ b/src/shared/unit-name.c +@@ -63,16 +63,13 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); + +-bool unit_name_is_valid(const char *n, enum template_valid template_ok) { ++bool unit_name_is_valid(const char *n, UnitNameFlags flags) { + const char *e, *i, *at; + +- /* Valid formats: +- * +- * string@instance.suffix +- * string.suffix +- */ ++ assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0); + +- assert(IN_SET(template_ok, TEMPLATE_VALID, TEMPLATE_INVALID)); ++ if (_unlikely_(flags == 0)) ++ return false; + + if (isempty(n)) + return false; +@@ -96,15 +93,22 @@ bool unit_name_is_valid(const char *n, enum template_valid template_ok) { + return false; + } + +- if (at) { +- if (at == n) +- return false; ++ if (at == n) ++ return false; + +- if (template_ok != TEMPLATE_VALID && at+1 == e) +- return false; +- } ++ if (flags & UNIT_NAME_PLAIN) ++ if (!at) ++ return true; ++ ++ if (flags & UNIT_NAME_INSTANCE) ++ if (at && e > at + 1) ++ return true; ++ ++ if (flags & UNIT_NAME_TEMPLATE) ++ if (at && e == at + 1) ++ return true; + +- return true; ++ return false; + } + + bool unit_instance_is_valid(const char *i) { +diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h +index 6f139cc..4364860 100644 +--- a/src/shared/unit-name.h ++++ b/src/shared/unit-name.h +@@ -107,6 +107,13 @@ enum UnitDependency { + _UNIT_DEPENDENCY_INVALID = -1 + }; + ++typedef enum UnitNameFlags { ++ UNIT_NAME_PLAIN = 1, /* Allow foo.service */ ++ UNIT_NAME_INSTANCE = 2, /* Allow foo@bar.service */ ++ UNIT_NAME_TEMPLATE = 4, /* Allow foo@.service */ ++ UNIT_NAME_ANY = UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE, ++} UnitNameFlags; ++ + const char *unit_type_to_string(UnitType i) _const_; + UnitType unit_type_from_string(const char *s) _pure_; + +@@ -117,12 +124,7 @@ int unit_name_to_instance(const char *n, char **instance); + char* unit_name_to_prefix(const char *n); + char* unit_name_to_prefix_and_instance(const char *n); + +-enum template_valid { +- TEMPLATE_INVALID, +- TEMPLATE_VALID, +-}; +- +-bool unit_name_is_valid(const char *n, enum template_valid template_ok) _pure_; ++bool unit_name_is_valid(const char *n, UnitNameFlags flags) _pure_; + bool unit_prefix_is_valid(const char *p) _pure_; + bool unit_instance_is_valid(const char *i) _pure_; + +diff --git a/src/shared/util.c b/src/shared/util.c +index a24aa7f..036677e 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -1094,6 +1094,27 @@ int readlink_and_canonicalize(const char *p, char **r) { + return 0; + } + ++ ++int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) { ++ _cleanup_free_ char *target = NULL, *t = NULL; ++ const char *full; ++ int r; ++ ++ full = prefix_roota(root, path); ++ r = readlink_malloc(full, &target); ++ if (r < 0) ++ return r; ++ ++ t = file_in_same_dir(path, target); ++ if (!t) ++ return -ENOMEM; ++ ++ *ret = t; ++ t = NULL; ++ ++ return 0; ++} ++ + int reset_all_signal_handlers(void) { + int sig, r = 0; + +diff --git a/src/shared/util.h b/src/shared/util.h +index b4a4a49..a441e44 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -281,6 +281,7 @@ int readlink_malloc(const char *p, char **r); + int readlink_value(const char *p, char **ret); + int readlink_and_make_absolute(const char *p, char **r); + int readlink_and_canonicalize(const char *p, char **r); ++int readlink_and_make_absolute_root(const char *root, const char *path, char **ret); + + int reset_all_signal_handlers(void); + int reset_signal_mask(void); +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index bf5bb39..95ddf3b 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -1304,7 +1304,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { + if (u->state == UNIT_FILE_MASKED || + u->state == UNIT_FILE_MASKED_RUNTIME || + u->state == UNIT_FILE_DISABLED || +- u->state == UNIT_FILE_INVALID) { ++ u->state == UNIT_FILE_BAD) { + on = ansi_highlight_red(); + off = ansi_highlight_off(); + } else if (u->state == UNIT_FILE_ENABLED) { +@@ -5637,8 +5637,8 @@ static int unit_is_enabled(sd_bus *bus, char **args) { + STRV_FOREACH(name, names) { + UnitFileState state; + +- state = unit_file_get_state(arg_scope, arg_root, *name); +- if (state < 0) ++ r = unit_file_get_state(arg_scope, arg_root, *name, &state); ++ if (r < 0) + return log_error_errno(state, "Failed to get unit file state for %s: %m", *name); + + if (state == UNIT_FILE_ENABLED || +diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c +index d60e75a..7e0e7fc 100644 +--- a/src/sysv-generator/sysv-generator.c ++++ b/src/sysv-generator/sysv-generator.c +@@ -712,6 +712,7 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { + + static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + char **path; ++ int r; + + STRV_FOREACH(path, lp->sysvinit_path) { + _cleanup_closedir_ DIR *d = NULL; +@@ -728,7 +729,6 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + _cleanup_free_ char *fpath = NULL, *name = NULL; + _cleanup_free_ SysvStub *service = NULL; + struct stat st; +- int r; + + if (hidden_file(de->d_name)) + continue; +@@ -755,8 +755,12 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { + if (!fpath) + return log_oom(); + +- if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) { +- log_debug("Native unit for %s already exists, skipping", name); ++ r = unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name, NULL); ++ if (r < 0 && r != -ENOENT) { ++ log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); ++ continue; ++ } else if (r >= 0) { ++ log_debug("Native unit for %s already exists, skipping.", name); + continue; + } + +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +new file mode 100644 +index 0000000..89d91d3 +--- /dev/null ++++ b/src/test/test-install-root.c +@@ -0,0 +1,663 @@ ++/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2011 Lennart Poettering ++ ++ 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 . ++***/ ++ ++#include "fileio.h" ++#include "install.h" ++#include "mkdir.h" ++#include "util.h" ++ ++static void test_basic_mask_and_enable(const char *root) { ++ const char *p; ++ UnitFileState state; ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/a.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/b.service"); ++ assert_se(symlink("a.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/c.service"); ++ assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/d.service"); ++ assert_se(symlink("c.service", p) >= 0); ++ ++ /* This one is interesting, as d follows a relative, then an absolute symlink */ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/dev/null")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); ++ ++ /* Enabling a masked unit should fail! */ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ /* Enabling it again should succeed but be a NOP */ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); ++ assert_se(n_changes == 0); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ /* Disabling a disabled unit must suceed but be a NOP */ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 0); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ /* Let's enable this indirectly via a symlink */ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ /* Let's try to reenable */ ++ ++ assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 2); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); ++ assert_se(streq(changes[0].path, p)); ++ assert_se(changes[1].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service")); ++ assert_se(streq(changes[1].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++} ++ ++static void test_linked_units(const char *root) { ++ const char *p, *q; ++ UnitFileState state; ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0, i; ++ ++ /* ++ * We'll test three cases here: ++ * ++ * a) a unit file in /opt, that we use "systemctl link" and ++ * "systemctl enable" on to make it available to the system ++ * ++ * b) a unit file in /opt, that is statically linked into ++ * /usr/lib/systemd/system, that "enable" should work on ++ * correctly. ++ * ++ * c) a unit file in /opt, that is linked into ++ * /etc/systemd/system, and where "enable" should result in ++ * -ELOOP, since using information from /etc to generate ++ * information in /etc should not be allowed. ++ */ ++ ++ p = strjoina(root, "/opt/linked.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/opt/linked2.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/opt/linked3.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/linked2.service"); ++ assert_se(symlink("/opt/linked2.service", p) >= 0); ++ ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked3.service"); ++ assert_se(symlink("/opt/linked3.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); ++ ++ /* First, let's link the unit into the search path */ ++ assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/opt/linked.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); ++ ++ /* Let's unlink it from the search path again */ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ ++ /* Now, let's not just link it, but also enable it */ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 2); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); ++ q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); ++ for (i = 0 ; i < n_changes; i++) { ++ assert_se(changes[i].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[i].source, "/opt/linked.service")); ++ ++ if (p && streq(changes[i].path, p)) ++ p = NULL; ++ else if (q && streq(changes[i].path, q)) ++ q = NULL; ++ else ++ assert_not_reached("wut?"); ++ } ++ assert(!p && !q); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ /* And let's unlink it again */ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 2); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); ++ q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); ++ for (i = 0; i < n_changes; i++) { ++ assert_se(changes[i].type == UNIT_FILE_UNLINK); ++ ++ if (p && streq(changes[i].path, p)) ++ p = NULL; ++ else if (q && streq(changes[i].path, q)) ++ q = NULL; ++ else ++ assert_not_reached("wut?"); ++ } ++ assert(!p && !q); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 2); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service"); ++ q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service"); ++ for (i = 0 ; i < n_changes; i++) { ++ assert_se(changes[i].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[i].source, "/opt/linked2.service")); ++ ++ if (p && streq(changes[i].path, p)) ++ p = NULL; ++ else if (q && streq(changes[i].path, q)) ++ q = NULL; ++ else ++ assert_not_reached("wut?"); ++ } ++ assert(!p && !q); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) == -ELOOP); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++} ++ ++static void test_default(const char *root) { ++ _cleanup_free_ char *def = NULL; ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ const char *p; ++ ++ p = strjoina(root, "/usr/lib/systemd/system/test-default-real.target"); ++ assert_se(write_string_file(p, "# pretty much empty") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/test-default.target"); ++ assert_se(symlink("test-default-real.target", p) >= 0); ++ ++ assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); ++ ++ assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT); ++ assert_se(n_changes == 0); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); ++ ++ assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "test-default.target", false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/default.target"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0); ++ assert_se(streq_ptr(def, "test-default-real.target")); ++} ++ ++static void test_add_dependency(const char *root) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ const char *p; ++ ++ p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-target.target"); ++ assert_se(write_string_file(p, "# pretty much empty") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-target.target"); ++ assert_se(symlink("real-add-dependency-test-target.target", p) >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-service.service"); ++ assert_se(write_string_file(p, "# pretty much empty") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); ++ assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); ++ ++ assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++} ++ ++static void test_template_enable(const char *root) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ UnitFileState state; ++ const char *p; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/template@.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "DefaultInstance=def\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service"); ++ assert_se(symlink("template@.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@def.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++} ++ ++static void test_indirect(const char *root) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0; ++ UnitFileState state; ++ const char *p; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/indirecta.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "Also=indirectb.service\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/indirectb.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/indirectc.service"); ++ assert_se(symlink("indirecta.service", p) >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ ++ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++} ++ ++static void test_preset_and_list(const char *root) { ++ UnitFileChange *changes = NULL; ++ unsigned n_changes = 0, i; ++ const char *p, *q; ++ UnitFileState state; ++ bool got_yes = false, got_no = false; ++ Iterator j; ++ UnitFileList *fl; ++ Hashmap *h; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); ++ assert_se(write_string_file(p, ++ "[Install]\n" ++ "WantedBy=multi-user.target\n") >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); ++ assert_se(write_string_file(p, ++ "enable *-yes.*\n" ++ "disable *\n") >= 0); ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_SYMLINK); ++ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); ++ assert_se(n_changes == 1); ++ assert_se(changes[0].type == UNIT_FILE_UNLINK); ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); ++ assert_se(streq(changes[0].path, p)); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ assert_se(n_changes == 0); ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); ++ ++ assert_se(n_changes > 0); ++ ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); ++ ++ for (i = 0; i < n_changes; i++) { ++ ++ if (changes[i].type == UNIT_FILE_SYMLINK) { ++ assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service")); ++ assert_se(streq(changes[i].path, p)); ++ } else ++ assert_se(changes[i].type == UNIT_FILE_UNLINK); ++ } ++ ++ unit_file_changes_free(changes, n_changes); ++ changes = NULL; n_changes = 0; ++ ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); ++ ++ assert_se(h = hashmap_new(&string_hash_ops)); ++ assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h) >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); ++ q = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); ++ ++ HASHMAP_FOREACH(fl, h, j) { ++ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0); ++ assert_se(fl->state == state); ++ ++ if (streq(fl->path, p)) { ++ got_yes = true; ++ assert_se(fl->state == UNIT_FILE_ENABLED); ++ } else if (streq(fl->path, q)) { ++ got_no = true; ++ assert_se(fl->state == UNIT_FILE_DISABLED); ++ } else ++ assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT)); ++ } ++ ++ unit_file_list_free(h); ++ ++ assert_se(got_yes && got_no); ++} ++ ++int main(int argc, char *argv[]) { ++ char root[] = "/tmp/rootXXXXXX"; ++ const char *p; ++ ++ assert_se(mkdtemp(root)); ++ ++ p = strjoina(root, "/usr/lib/systemd/system/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ p = strjoina(root, "/run/systemd/system/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ p = strjoina(root, "/opt/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ p = strjoina(root, "/usr/lib/systemd/system-preset/"); ++ assert_se(mkdir_p(p, 0755) >= 0); ++ ++ test_basic_mask_and_enable(root); ++ test_linked_units(root); ++ test_default(root); ++ test_add_dependency(root); ++ test_template_enable(root); ++ test_indirect(root); ++ test_preset_and_list(root); ++ ++ assert_se(rm_rf_dangerous(root, false, true, false)); ++ ++ return 0; ++} +diff --git a/src/test/test-install.c b/src/test/test-install.c +index 467970b..08a1faf 100644 +--- a/src/test/test-install.c ++++ b/src/test/test-install.c +@@ -50,17 +50,19 @@ int main(int argc, char* argv[]) { + const char *const files2[] = { "/home/lennart/test.service", NULL }; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; ++ UnitFileState state = 0; + + h = hashmap_new(&string_hash_ops); + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + assert_se(r == 0); + + HASHMAP_FOREACH(p, h, i) { +- UnitFileState s; ++ UnitFileState s = _UNIT_FILE_STATE_INVALID; + +- s = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path)); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s); + +- assert_se(p->state == s); ++ assert_se((r < 0 && p->state == UNIT_FILE_BAD) || ++ (p->state == s)); + + fprintf(stderr, "%s (%s)\n", + p->path, +@@ -82,7 +84,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_ENABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_ENABLED); + + log_error("disable"); + +@@ -95,7 +99,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_DISABLED); + + log_error("mask"); + changes = NULL; +@@ -110,7 +116,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_MASKED); + + log_error("unmask"); + changes = NULL; +@@ -125,7 +133,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_DISABLED); + + log_error("mask"); + changes = NULL; +@@ -137,7 +147,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_MASKED); + + log_error("disable"); + changes = NULL; +@@ -152,7 +164,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_MASKED); + + log_error("umask"); + changes = NULL; +@@ -164,7 +178,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_DISABLED); + + log_error("enable files2"); + changes = NULL; +@@ -176,19 +192,22 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_ENABLED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r < 0); + + log_error("link files2"); + changes = NULL; +@@ -200,19 +219,22 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_LINKED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r < 0); + + log_error("link files2"); + changes = NULL; +@@ -224,7 +246,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_LINKED); + + log_error("reenable files2"); + changes = NULL; +@@ -236,19 +260,22 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_ENABLED); + + log_error("disable files2"); + changes = NULL; + n_changes = 0; + +- r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); ++ r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + assert_se(r >= 0); + + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); ++ assert_se(r < 0); + log_error("preset files"); + changes = NULL; + n_changes = 0; +@@ -259,7 +286,9 @@ int main(int argc, char* argv[]) { + dump_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); + +- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0])) == UNIT_FILE_ENABLED); ++ r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state); ++ assert_se(r >= 0); ++ assert_se(state == UNIT_FILE_ENABLED); + + return 0; + } diff --git a/SOURCES/0297-core-look-for-instance-when-processing-template-name.patch b/SOURCES/0297-core-look-for-instance-when-processing-template-name.patch new file mode 100644 index 0000000..6179f44 --- /dev/null +++ b/SOURCES/0297-core-look-for-instance-when-processing-template-name.patch @@ -0,0 +1,41 @@ +From 0e6ec33b5e8c8790e60d1b79801dc360dad010d3 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 16 Mar 2016 15:47:18 +0100 +Subject: [PATCH] core: look for instance when processing template name + +If first attempt to merge units failed and we are trying to do +merge the other way around and at the same time we are working with +template name, then other unit can't possibly be template, because it is +not possible to have template unit running, only instances of the +template. Thus we need to look for already active instance instead. + +rhel-only (upstream review pending) + +Related: #1159308 +--- + src/core/load-fragment.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 70c0918..b188ec9 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3472,8 +3472,17 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { + /* Hmm, we couldn't merge the other unit into + * ours? Then let's try it the other way + * round */ ++ if (unit_name_is_template(k) && (*u)->instance) { ++ _cleanup_free_ char *instance = NULL; ++ ++ instance = unit_name_replace_instance(k, (*u)->instance); ++ if(!instance) ++ return -ENOMEM; ++ other = manager_get_unit((*u)->manager, instance); ++ ++ } else ++ other = manager_get_unit((*u)->manager, k); + +- other = manager_get_unit((*u)->manager, k); + free(k); + + if (other) { diff --git a/SOURCES/0298-core-improve-error-message-when-starting-template-wi.patch b/SOURCES/0298-core-improve-error-message-when-starting-template-wi.patch new file mode 100644 index 0000000..c18cb11 --- /dev/null +++ b/SOURCES/0298-core-improve-error-message-when-starting-template-wi.patch @@ -0,0 +1,30 @@ +From 9b33863a2cfa31bbe57bab685776b64731f528f1 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 30 Mar 2016 13:49:50 +0200 +Subject: [PATCH] core: improve error message when starting template without + instance + +Cherry-picked from: 5d512d54429aa9d2f4a0ca215bb2e982db720d6b +Resolves: #1142369 +--- + src/core/manager.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index bde17ce..bb50503 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1328,8 +1328,12 @@ int manager_load_unit_prepare( + + t = unit_name_to_type(name); + +- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) ++ if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { ++ if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) ++ return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is missing the instance name.", name); ++ + return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); ++ } + + ret = manager_get_unit(m, name); + if (ret) { diff --git a/SOURCES/0299-man-tmpfiles.d-add-note-about-permissions-and-owners.patch b/SOURCES/0299-man-tmpfiles.d-add-note-about-permissions-and-owners.patch new file mode 100644 index 0000000..2468eac --- /dev/null +++ b/SOURCES/0299-man-tmpfiles.d-add-note-about-permissions-and-owners.patch @@ -0,0 +1,28 @@ +From b0edbac36cd75bfd5624f20884043553da14ced2 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 13 Jan 2016 08:41:54 +0100 +Subject: [PATCH] man/tmpfiles.d: add note about permissions and ownership of + symlinks + +...because this is might not be obvious. + +Cherry-picked from: b908bb63c41eaf3c44004b6b737d105c39df2075 +Resolves: #1296288 +--- + man/tmpfiles.d.xml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml +index 9b4e11c..fc1fe13 100644 +--- a/man/tmpfiles.d.xml ++++ b/man/tmpfiles.d.xml +@@ -187,7 +187,8 @@ + be removed and be replaced by the symlink. If the argument + is omitted, symlinks to files with the same name residing in + the directory /usr/share/factory/ are +- created. ++ created. Note that permissions and ownership on symlinks ++ are ignored. + + + diff --git a/SOURCES/0300-tmpfiles-don-t-follow-symlinks-when-adjusting-ACLs-f.patch b/SOURCES/0300-tmpfiles-don-t-follow-symlinks-when-adjusting-ACLs-f.patch new file mode 100644 index 0000000..973aaf0 --- /dev/null +++ b/SOURCES/0300-tmpfiles-don-t-follow-symlinks-when-adjusting-ACLs-f.patch @@ -0,0 +1,185 @@ +From 595a93d716680715a751737ec2f87b06ea582763 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 13 Apr 2015 15:16:54 +0200 +Subject: [PATCH] tmpfiles: don't follow symlinks when adjusting ACLs, fille + attributes, access modes or ownership + +Cherry-picked from: 48b8aaa82724bc2d8440470f414fb0d2416f29c +Resolves: #1296288 +--- + src/tmpfiles/tmpfiles.c | 112 ++++++++++++++++++++++++++++++++---------------- + 1 file changed, 74 insertions(+), 38 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index d0e6567..64c733a 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -570,51 +570,69 @@ finish: + } + + static int path_set_perms(Item *i, const char *path) { ++ _cleanup_close_ int fd = -1; + struct stat st; +- bool st_valid; + + assert(i); + assert(path); + +- st_valid = stat(path, &st) == 0; ++ /* We open the file with O_PATH here, to make the operation ++ * somewhat atomic. Also there's unfortunately no fchmodat() ++ * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via ++ * O_PATH. */ ++ ++ fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); ++ if (fd < 0) ++ return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path); ++ ++ if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0) ++ return log_error_errno(errno, "Failed to fstat() file %s: %m", path); ++ ++ if (S_ISLNK(st.st_mode)) ++ log_debug("Skipping mode an owner fix for symlink %s.", path); ++ else { ++ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; ++ xsprintf(fn, "/proc/self/fd/%i", fd); + +- /* not using i->path directly because it may be a glob */ +- if (i->mode_set) { +- mode_t m = i->mode; ++ /* not using i->path directly because it may be a glob */ ++ if (i->mode_set) { ++ mode_t m = i->mode; + +- if (i->mask_perms && st_valid) { +- if (!(st.st_mode & 0111)) +- m &= ~0111; +- if (!(st.st_mode & 0222)) ++ if (i->mask_perms) { ++ if (!(st.st_mode & 0111)) ++ m &= ~0111; ++ if (!(st.st_mode & 0222)) + m &= ~0222; +- if (!(st.st_mode & 0444)) +- m &= ~0444; +- if (!S_ISDIR(st.st_mode)) +- m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */ +- } ++ if (!(st.st_mode & 0444)) ++ m &= ~0444; ++ if (!S_ISDIR(st.st_mode)) ++ m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */ ++ } + +- if (st_valid && m == (st.st_mode & 07777)) +- log_debug("\"%s\" has right mode %o", path, st.st_mode); +- else { +- log_debug("chmod \"%s\" to mode %o", path, m); +- if (chmod(path, m) < 0) +- return log_error_errno(errno, "chmod(%s) failed: %m", path); ++ if (m == (st.st_mode & 07777)) ++ log_debug("\"%s\" has right mode %o", path, st.st_mode); ++ else { ++ log_debug("chmod \"%s\" to mode %o", path, m); ++ if (chmod(fn, m) < 0) ++ return log_error_errno(errno, "chmod(%s) failed: %m", path); ++ } + } +- } +- +- if ((!st_valid || i->uid != st.st_uid || i->gid != st.st_gid) && +- (i->uid_set || i->gid_set)) { +- log_debug("chown \"%s\" to "UID_FMT"."GID_FMT, +- path, +- i->uid_set ? i->uid : UID_INVALID, +- i->gid_set ? i->gid : GID_INVALID); +- if (chown(path, +- i->uid_set ? i->uid : UID_INVALID, +- i->gid_set ? i->gid : GID_INVALID) < 0) + ++ if ((i->uid != st.st_uid || i->gid != st.st_gid) && ++ (i->uid_set || i->gid_set)) { ++ log_debug("chown \"%s\" to "UID_FMT"."GID_FMT, ++ path, ++ i->uid_set ? i->uid : UID_INVALID, ++ i->gid_set ? i->gid : GID_INVALID); ++ if (chown(fn, ++ i->uid_set ? i->uid : UID_INVALID, ++ i->gid_set ? i->gid : GID_INVALID) < 0) + return log_error_errno(errno, "chown(%s) failed: %m", path); ++ } + } + ++ fd = safe_close(fd); ++ + return label_fix(path, false, false); + } + +@@ -699,10 +717,10 @@ static int get_acls_from_arg(Item *item) { + } + + #ifdef HAVE_ACL +-static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) { ++static int path_set_acl(const char *path, const char *pretty, acl_type_t type, acl_t acl, bool modify) { ++ _cleanup_(acl_free_charpp) char *t = NULL; + _cleanup_(acl_freep) acl_t dup = NULL; + int r; +- _cleanup_(acl_free_charpp) char *t = NULL; + + /* Returns 0 for success, positive error if already warned, + * negative error otherwise. */ +@@ -728,16 +746,16 @@ static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modif + return r; + + t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE); +- log_debug("\"%s\": setting %s ACL \"%s\"", path, ++ log_debug("Setting %s ACL %s on %s.", + type == ACL_TYPE_ACCESS ? "access" : "default", +- strna(t)); ++ strna(t), pretty); + + r = acl_set_file(path, type, dup); + if (r < 0) + return -log_error_errno(errno, + "Setting %s ACL \"%s\" on %s failed: %m", + type == ACL_TYPE_ACCESS ? "access" : "default", +- strna(t), path); ++ strna(t), pretty); + + return 0; + } +@@ -746,14 +764,32 @@ static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modif + static int path_set_acls(Item *item, const char *path) { + int r = 0; + #ifdef HAVE_ACL ++ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; ++ _cleanup_close_ int fd = -1; ++ struct stat st; ++ + assert(item); + assert(path); + ++ fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); ++ if (fd < 0) ++ return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path); ++ ++ if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0) ++ return log_error_errno(errno, "Failed to fstat() file %s: %m", path); ++ ++ if (S_ISLNK(st.st_mode)) { ++ log_debug("Skipping ACL fix for symlink %s.", path); ++ return 0; ++ } ++ ++ xsprintf(fn, "/proc/self/fd/%i", fd); ++ + if (item->acl_access) +- r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force); ++ r = path_set_acl(fn, path, ACL_TYPE_ACCESS, item->acl_access, item->force); + + if (r == 0 && item->acl_default) +- r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force); ++ r = path_set_acl(fn, path, ACL_TYPE_DEFAULT, item->acl_default, item->force); + + if (r > 0) + return -r; /* already warned */ diff --git a/SOURCES/0301-udev-filter-out-non-sensically-high-onboard-indexes-.patch b/SOURCES/0301-udev-filter-out-non-sensically-high-onboard-indexes-.patch new file mode 100644 index 0000000..b261d9c --- /dev/null +++ b/SOURCES/0301-udev-filter-out-non-sensically-high-onboard-indexes-.patch @@ -0,0 +1,43 @@ +From 0fa424a08a31af512a698b60b497cfc0cf0554e0 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 25 Jan 2016 17:16:27 +0100 +Subject: [PATCH] udev: filter out non-sensically high onboard indexes reported + by the kernel + +Let's not accept onboard interface indexes, that are so high that they are obviously non-sensical. + +Fixes: #2407 + +Cherry-picked from: 6c1e69f9456d022f14dd00737126cfa4d9cca10 +Resolves: #1230210 +--- + src/udev/udev-builtin-net_id.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index ffd6ea4..19e1f26 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -101,6 +101,8 @@ + #include "udev.h" + #include "fileio.h" + ++#define ONBOARD_INDEX_MAX (16*1024-1) ++ + enum netname_type{ + NET_UNDEF, + NET_PCI, +@@ -147,6 +149,13 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { + if (idx <= 0) + return -EINVAL; + ++ /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for ++ * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary ++ * cut-off, which is somewhere beyond the realistic number of physical network interface a system might ++ * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */ ++ if (idx > ONBOARD_INDEX_MAX) ++ return -ENOENT; ++ + /* kernel provided port index for multiple ports on a single PCI function */ + attr = udev_device_get_sysattr_value(dev, "dev_port"); + if (attr) diff --git a/SOURCES/0302-test-execute-add-tests-for-RuntimeDirectory.patch b/SOURCES/0302-test-execute-add-tests-for-RuntimeDirectory.patch new file mode 100644 index 0000000..db487ec --- /dev/null +++ b/SOURCES/0302-test-execute-add-tests-for-RuntimeDirectory.patch @@ -0,0 +1,74 @@ +From fb798a267d2bad8df98f49c2a4a309efa5569759 Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Mon, 21 Sep 2015 15:36:07 +0200 +Subject: [PATCH] test-execute: add tests for RuntimeDirectory + +Cherry-picked from: cc3ddc851fbe5adf9dfc7e4a702a8b5b6a1186d6 +Resolves: #1324826 +--- + src/test/test-execute.c | 7 +++++++ + test/exec-runtimedirectory-mode.service | 8 ++++++++ + test/exec-runtimedirectory.service | 7 +++++++ + 3 files changed, 22 insertions(+) + create mode 100644 test/exec-runtimedirectory-mode.service + create mode 100644 test/exec-runtimedirectory.service + +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 00f3607..90b1c87 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -141,6 +141,11 @@ static void test_exec_umask(Manager *m) { + test(m, "exec-umask-0177.service", 0, CLD_EXITED); + } + ++static void test_exec_runtimedirectory(Manager *m) { ++ test(m, "exec-runtimedirectory.service", 0, CLD_EXITED); ++ test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); ++} ++ + int main(int argc, char *argv[]) { + test_function_t tests[] = { + test_exec_workingdirectory, +@@ -154,6 +159,7 @@ int main(int argc, char *argv[]) { + test_exec_group, + test_exec_environment, + test_exec_umask, ++ test_exec_runtimedirectory, + NULL, + }; + test_function_t *test = NULL; +@@ -169,6 +175,7 @@ int main(int argc, char *argv[]) { + return EXIT_TEST_SKIP; + } + ++ assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0); + assert_se(set_unit_path(TEST_DIR ":") >= 0); + + r = manager_new(SYSTEMD_USER, true, &m); +diff --git a/test/exec-runtimedirectory-mode.service b/test/exec-runtimedirectory-mode.service +new file mode 100644 +index 0000000..ba6d7ee +--- /dev/null ++++ b/test/exec-runtimedirectory-mode.service +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Test for RuntimeDirectoryMode ++ ++[Service] ++ExecStart=/bin/sh -c 's=$(stat -c %a /tmp/test-exec_runtimedirectory-mode); echo $s; exit $(test $s = "750")' ++Type=oneshot ++RuntimeDirectory=test-exec_runtimedirectory-mode ++RuntimeDirectoryMode=0750 +diff --git a/test/exec-runtimedirectory.service b/test/exec-runtimedirectory.service +new file mode 100644 +index 0000000..c12a6c6 +--- /dev/null ++++ b/test/exec-runtimedirectory.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for RuntimeDirectory ++ ++[Service] ++ExecStart=/bin/sh -c 'exit $(test -d /tmp/test-exec_runtimedirectory)' ++Type=oneshot ++RuntimeDirectory=test-exec_runtimedirectory diff --git a/SOURCES/0303-core-fix-group-ownership-when-Group-is-set.patch b/SOURCES/0303-core-fix-group-ownership-when-Group-is-set.patch new file mode 100644 index 0000000..5d195a6 --- /dev/null +++ b/SOURCES/0303-core-fix-group-ownership-when-Group-is-set.patch @@ -0,0 +1,84 @@ +From f2300a5c3226d3a66d77c34ae811401c638f430f Mon Sep 17 00:00:00 2001 +From: Ronny Chevalier +Date: Mon, 21 Sep 2015 15:45:51 +0200 +Subject: [PATCH] core: fix group ownership when Group is set + +When Group is set in the unit, the runtime directories are owned by +this group and not the default group of the user (same for cgroup paths +and standard outputs) + +Fix #1231 + +Cherry-picked from: 5bc7452b3219456e07f931e40da30bb94a884293 +Resolves: #1324826 +--- + src/core/execute.c | 19 +++++++++++-------- + src/test/test-execute.c | 1 + + test/exec-runtimedirectory-owner.service | 9 +++++++++ + 3 files changed, 21 insertions(+), 8 deletions(-) + create mode 100644 test/exec-runtimedirectory-owner.service + +diff --git a/src/core/execute.c b/src/core/execute.c +index 1815e3d..8172c8b 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -629,14 +629,6 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_ + * we avoid NSS lookups for gid=0. */ + + if (context->group || username) { +- +- if (context->group) { +- const char *g = context->group; +- +- if ((r = get_group_creds(&g, &gid)) < 0) +- return r; +- } +- + /* First step, initialize groups from /etc/groups */ + if (username && gid != 0) { + if (initgroups(username, gid) < 0) +@@ -1374,6 +1366,17 @@ static int exec_child( + } + } + ++ if (context->group) { ++ const char *g = context->group; ++ ++ r = get_group_creds(&g, &gid); ++ if (r < 0) { ++ *exit_status = EXIT_GROUP; ++ return r; ++ } ++ } ++ ++ + /* If a socket is connected to STDIN/STDOUT/STDERR, we + * must sure to drop O_NONBLOCK */ + if (socket_fd >= 0) +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 90b1c87..38522a1 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -144,6 +144,7 @@ static void test_exec_umask(Manager *m) { + static void test_exec_runtimedirectory(Manager *m) { + test(m, "exec-runtimedirectory.service", 0, CLD_EXITED); + test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); ++ test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + } + + int main(int argc, char *argv[]) { +diff --git a/test/exec-runtimedirectory-owner.service b/test/exec-runtimedirectory-owner.service +new file mode 100644 +index 0000000..077e08d +--- /dev/null ++++ b/test/exec-runtimedirectory-owner.service +@@ -0,0 +1,9 @@ ++[Unit] ++Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set) ++ ++[Service] ++ExecStart=/bin/sh -c 'f=/tmp/test-exec_runtimedirectory-owner;g=$(stat -c %G $f); echo "$g"; exit $(test $g = "nobody")' ++Type=oneshot ++Group=nobody ++User=root ++RuntimeDirectory=test-exec_runtimedirectory-owner diff --git a/SOURCES/0304-fstab-generator-cescape-device-name-in-root-fsck-ser.patch b/SOURCES/0304-fstab-generator-cescape-device-name-in-root-fsck-ser.patch new file mode 100644 index 0000000..3928b66 --- /dev/null +++ b/SOURCES/0304-fstab-generator-cescape-device-name-in-root-fsck-ser.patch @@ -0,0 +1,49 @@ +From e591c1a47c067cd2d14dca569cc9f0cce9072200 Mon Sep 17 00:00:00 2001 +From: Andrei Borzenkov +Date: Wed, 3 Jun 2015 20:50:59 +0300 +Subject: [PATCH] fstab-generator: cescape device name in root-fsck service + +We unescape ExecStart line when parsing it, so escape device name +before adding it to unit file. + +fixes #50 + +Cherry-picked from: fa05e97 +Resolves: #1306126 +--- + src/shared/generator.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/shared/generator.c b/src/shared/generator.c +index 3af84a3..be8e24e 100644 +--- a/src/shared/generator.c ++++ b/src/shared/generator.c +@@ -35,8 +35,13 @@ + static int write_fsck_sysroot_service(const char *dir, const char *what) { + const char *unit; + _cleanup_free_ char *device = NULL; ++ _cleanup_free_ char *escaped; + _cleanup_fclose_ FILE *f = NULL; + ++ escaped = cescape(what); ++ if (!escaped) ++ return log_oom(); ++ + unit = strjoina(dir, "/systemd-fsck-root.service"); + log_debug("Creating %s", unit); + +@@ -61,11 +66,12 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { + "[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" +- "ExecStart=" SYSTEMD_FSCK_PATH " %2$s\n" ++ "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n" + "TimeoutSec=0\n", + program_invocation_short_name, + what, +- device); ++ device, ++ escaped); + + fflush(f); + if (ferror(f)) diff --git a/SOURCES/0305-core-add-new-RandomSec-setting-for-time-units.patch b/SOURCES/0305-core-add-new-RandomSec-setting-for-time-units.patch new file mode 100644 index 0000000..57c910c --- /dev/null +++ b/SOURCES/0305-core-add-new-RandomSec-setting-for-time-units.patch @@ -0,0 +1,227 @@ +From 338b8f9bca1cd7bd65123808fc7f7b2773e637db Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 18 Nov 2015 13:37:30 +0100 +Subject: [PATCH] core: add new RandomSec= setting for time units + +This allows configuration of a random time on top of the elapse events, +in order to spread time events in a network evenly across a range. + +Cherry-picked from: 744c7693751830149ae78fdaf95c6c6f99d59f07 +Resolves: #1305279 +--- + man/systemd.timer.xml | 43 ++++++++++++++++++++++++++++++----- + src/core/dbus-timer.c | 17 ++++++++++++++ + src/core/load-fragment-gperf.gperf.m4 | 1 + + src/core/timer.c | 28 +++++++++++++++++++++++ + src/core/timer.h | 1 + + src/libsystemd/sd-bus/bus-util.c | 16 +++++++++++++ + 6 files changed, 100 insertions(+), 6 deletions(-) + +diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml +index 20890f2..bdd14d8 100644 +--- a/man/systemd.timer.xml ++++ b/man/systemd.timer.xml +@@ -180,13 +180,12 @@ + OnUnitInactiveSec= and ending the time + configured with AccuracySec= later. Within + this time window, the expiry time will be placed at a +- host-specific, randomized but stable position that is ++ host-specific, randomized, but stable position that is + synchronized between all local timer units. This is done in +- order to distribute the wake-up time in networked +- installations, as well as optimizing power consumption to +- suppress unnecessary CPU wake-ups. To get best accuracy, set +- this option to 1us. Note that the timer is still subject to +- the timer slack configured via ++ order to optimize power consumption to suppress unnecessary ++ CPU wake-ups. To get best accuracy, set this option to ++ 1us. Note that the timer is still subject to the timer slack ++ configured via + systemd-system.conf5's + TimerSlackNSec= setting. See + prctl2 +@@ -194,6 +193,38 @@ + this value as high as possible and as low as + necessary. + ++ ++ ++ RandomSec= ++ ++ Delay the timer by a randomly selected, evenly ++ distributed amount of time between 0 and the specified time ++ value. Defaults to 0, indicating that no randomized delay ++ shall be applied. Each timer unit will determine this delay ++ randomly each time it is started, and the delay will simply be ++ added on top of the next determined elapsing time. This is ++ useful to stretch dispatching of similarly configured timer ++ events over a certain amount time, to avoid that they all fire ++ at the same time, possibly resulting in resource ++ congestion. Note the relation to ++ AccuracySec= above: the latter allows the ++ service manager to coalesce timer events within a specified ++ time range in order to minimize wakeups, the former does the ++ opposite: it stretches timer events over a time range, to make ++ it unlikely that they fire simultaneously. If ++ RandomSec= and ++ AccuracySec= are used in conjunction, first ++ the a randomized time is added, and the result is then ++ possibly shifted further to coalesce it with other timer ++ events possibly happening on the system. As mentioned above ++ AccuracySec= defaults to 1min and ++ RandomSec= to 0, thus encouraging ++ coalescing of timer events. In order to optimally stretch ++ timer events over a certain range of time, make sure to set ++ RandomSec= to a higher value, and ++ AccuracySec=1us. ++ ++ + + Unit= + +diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c +index 43e7852..cd7bf44 100644 +--- a/src/core/dbus-timer.c ++++ b/src/core/dbus-timer.c +@@ -181,6 +181,7 @@ const sd_bus_vtable bus_timer_vtable[] = { + BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("RandomUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +@@ -284,6 +285,22 @@ static int bus_timer_set_transient_property( + + return 1; + ++ } else if (streq(name, "RandomUSec")) { ++ usec_t u = 0; ++ ++ r = sd_bus_message_read(message, "t", &u); ++ if (r < 0) ++ return r; ++ ++ if (mode != UNIT_CHECK) { ++ char time[FORMAT_TIMESPAN_MAX]; ++ ++ t->random_usec = u; ++ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomSec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); ++ } ++ ++ return 1; ++ + } else if (streq(name, "WakeSystem")) { + + int b; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 5305984..5106a98 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -336,6 +336,7 @@ Timer.OnUnitInactiveSec, config_parse_timer, 0, + Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent) + Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system) + Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec) ++Timer.RandomSec, config_parse_sec, 0, offsetof(Timer, random_usec) + Timer.Unit, config_parse_trigger_unit, 0, 0 + m4_dnl + Path.PathExists, config_parse_path_spec, 0, 0 +diff --git a/src/core/timer.c b/src/core/timer.c +index 48cf9c1..972dd73 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -29,6 +29,7 @@ + #include "bus-util.h" + #include "bus-error.h" + #include "mkdir.h" ++#include "util.h" + + static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { + [TIMER_DEAD] = UNIT_INACTIVE, +@@ -315,6 +316,28 @@ static usec_t monotonic_to_boottime(usec_t t) { + return 0; + } + ++static void add_random(Timer *t, usec_t *v) { ++ char s[FORMAT_TIMESPAN_MAX]; ++ usec_t add; ++ ++ assert(t); ++ assert(*v); ++ ++ if (t->random_usec == 0) ++ return; ++ if (*v == USEC_INFINITY) ++ return; ++ ++ add = random_u64() % t->random_usec; ++ ++ if (*v + add < *v) /* overflow */ ++ *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */ ++ else ++ *v += add; ++ ++ log_unit_info(UNIT(t)->id, "Adding %s random time.", format_timespan(s, sizeof(s), add, 0)); ++} ++ + static void timer_enter_waiting(Timer *t, bool initial) { + bool found_monotonic = false, found_realtime = false; + usec_t ts_realtime, ts_monotonic; +@@ -431,6 +454,8 @@ static void timer_enter_waiting(Timer *t, bool initial) { + if (found_monotonic) { + char buf[FORMAT_TIMESPAN_MAX]; + ++ add_random(t, &t->next_elapse_monotonic_or_boottime); ++ + log_unit_debug(UNIT(t)->id, "%s: Monotonic timer elapses in %s.", + UNIT(t)->id, + format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0)); +@@ -460,6 +485,9 @@ static void timer_enter_waiting(Timer *t, bool initial) { + + if (found_realtime) { + char buf[FORMAT_TIMESTAMP_MAX]; ++ ++ add_random(t, &t->next_elapse_realtime); ++ + log_unit_debug(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime)); + + if (t->realtime_event_source) { +diff --git a/src/core/timer.h b/src/core/timer.h +index de412a0..b977245 100644 +--- a/src/core/timer.h ++++ b/src/core/timer.h +@@ -69,6 +69,7 @@ struct Timer { + Unit meta; + + usec_t accuracy_usec; ++ usec_t random_usec; + + LIST_HEAD(TimerValue, values); + usec_t next_elapse_realtime; +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 6d56150..5ecb3be 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1364,6 +1364,22 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + return bus_log_create_error(r); + + return 0; ++ } else if (streq(field, "RandomSec")) { ++ usec_t t; ++ ++ r = parse_sec(eq, &t); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse RandomSec= parameter: %s", eq); ++ ++ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomUSec"); ++ if (r < 0) ++ return bus_log_create_error(r); ++ ++ r = sd_bus_message_append(m, "v", "t", t); ++ if (r < 0) ++ return bus_log_create_error(r); ++ ++ return 0; + } + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); diff --git a/SOURCES/0306-core-rename-Random-to-RandomizedDelay.patch b/SOURCES/0306-core-rename-Random-to-RandomizedDelay.patch new file mode 100644 index 0000000..522a8a2 --- /dev/null +++ b/SOURCES/0306-core-rename-Random-to-RandomizedDelay.patch @@ -0,0 +1,118 @@ +From 510ba7ebe71c8e4e64ead26a44b330d2e4375d9c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 26 Nov 2015 16:32:41 -0500 +Subject: [PATCH] core: rename Random* to RandomizedDelay* + +The name RandomSec is too generic: "Sec" just specifies the default +unit type, and "Random" by itself is not enough. Rename to something +that should give the user general idea what the setting does without +looking at documentation. + +Cherry-picked from: 6f5d79986a9c98b9cacc83f865fed957e4e6e4e6 +Resolves: #1305279 +--- + man/systemd.timer.xml | 8 ++++---- + src/core/dbus-timer.c | 6 +++--- + src/core/load-fragment-gperf.gperf.m4 | 2 +- + src/libsystemd/sd-bus/bus-util.c | 6 +++--- + 4 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml +index bdd14d8..ab83b2c 100644 +--- a/man/systemd.timer.xml ++++ b/man/systemd.timer.xml +@@ -195,7 +195,7 @@ + + + +- RandomSec= ++ RandomizedDelaySec= + + Delay the timer by a randomly selected, evenly + distributed amount of time between 0 and the specified time +@@ -212,16 +212,16 @@ + time range in order to minimize wakeups, the former does the + opposite: it stretches timer events over a time range, to make + it unlikely that they fire simultaneously. If +- RandomSec= and ++ RandomizedDelaySec= and + AccuracySec= are used in conjunction, first + the a randomized time is added, and the result is then + possibly shifted further to coalesce it with other timer + events possibly happening on the system. As mentioned above + AccuracySec= defaults to 1min and +- RandomSec= to 0, thus encouraging ++ RandomizedDelaySec= to 0, thus encouraging + coalescing of timer events. In order to optimally stretch + timer events over a certain range of time, make sure to set +- RandomSec= to a higher value, and ++ RandomizedDelaySec= to a higher value, and + AccuracySec=1us. + + +diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c +index cd7bf44..478905a 100644 +--- a/src/core/dbus-timer.c ++++ b/src/core/dbus-timer.c +@@ -181,7 +181,7 @@ const sd_bus_vtable bus_timer_vtable[] = { + BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), +- SD_BUS_PROPERTY("RandomUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_VTABLE_END +@@ -285,7 +285,7 @@ static int bus_timer_set_transient_property( + + return 1; + +- } else if (streq(name, "RandomUSec")) { ++ } else if (streq(name, "RandomizedDelayUSec")) { + usec_t u = 0; + + r = sd_bus_message_read(message, "t", &u); +@@ -296,7 +296,7 @@ static int bus_timer_set_transient_property( + char time[FORMAT_TIMESPAN_MAX]; + + t->random_usec = u; +- unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomSec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); ++ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); + } + + return 1; +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 5106a98..85d9797 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -336,7 +336,7 @@ Timer.OnUnitInactiveSec, config_parse_timer, 0, + Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent) + Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system) + Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec) +-Timer.RandomSec, config_parse_sec, 0, offsetof(Timer, random_usec) ++Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_usec) + Timer.Unit, config_parse_trigger_unit, 0, 0 + m4_dnl + Path.PathExists, config_parse_path_spec, 0, 0 +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 5ecb3be..3a91836 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1364,14 +1364,14 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + return bus_log_create_error(r); + + return 0; +- } else if (streq(field, "RandomSec")) { ++ } else if (streq(field, "RandomizedDelaySec")) { + usec_t t; + + r = parse_sec(eq, &t); + if (r < 0) +- return log_error_errno(r, "Failed to parse RandomSec= parameter: %s", eq); ++ return log_error_errno(r, "Failed to parse RandomizedDelaySec= parameter: %s", eq); + +- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomUSec"); ++ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomizedDelayUSec"); + if (r < 0) + return bus_log_create_error(r); + diff --git a/SOURCES/0307-journal-remote-change-owner-of-var-log-journal-remot.patch b/SOURCES/0307-journal-remote-change-owner-of-var-log-journal-remot.patch new file mode 100644 index 0000000..fdc6b1e --- /dev/null +++ b/SOURCES/0307-journal-remote-change-owner-of-var-log-journal-remot.patch @@ -0,0 +1,26 @@ +From 1c6075b30786cefc73e41b2f1f5459006f37b616 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 15 Jan 2016 15:19:52 +0900 +Subject: [PATCH] journal-remote: change owner of /var/log/journal/remote and + create /var/lib/systemd/journal-upload + +Cherry-picked from: dcdd4411407067fa1e464dc26ab85ae598fcad7d +Resolves: #1327303 +--- + tmpfiles.d/systemd-remote.conf | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tmpfiles.d/systemd-remote.conf b/tmpfiles.d/systemd-remote.conf +index 1b8973a..e19230f 100644 +--- a/tmpfiles.d/systemd-remote.conf ++++ b/tmpfiles.d/systemd-remote.conf +@@ -7,5 +7,7 @@ + + # See tmpfiles.d(5) for details + +-z /var/log/journal/remote 2755 root systemd-journal-remote - - +-z /run/log/journal/remote 2755 root systemd-journal-remote - - ++d /var/lib/systemd/journal-upload 0755 systemd-journal-upload systemd-journal-upload - - ++ ++z /var/log/journal/remote 2755 systemd-journal-remote systemd-journal-remote - - ++z /run/log/journal/remote 2755 systemd-journal-remote systemd-journal-remote - - diff --git a/SOURCES/0308-Add-Seal-option-in-the-configuration-file-for-journa.patch b/SOURCES/0308-Add-Seal-option-in-the-configuration-file-for-journa.patch new file mode 100644 index 0000000..b0af3aa --- /dev/null +++ b/SOURCES/0308-Add-Seal-option-in-the-configuration-file-for-journa.patch @@ -0,0 +1,57 @@ +From f6a8db04fb20d142e514d805c613a1b3e70c454d Mon Sep 17 00:00:00 2001 +From: Michael Scherer +Date: Sun, 20 Dec 2015 13:23:33 +0100 +Subject: [PATCH] Add Seal option in the configuration file for journald-remote + +While journal received remotely can be sealed, it can only be done +on the command line using --seal, so for consistency, we will +also permit to set it in the configuration file. + +Cherry-picked from: 9d3737f13e9b38f88ed7acc800db66c2f025fac9 +Resolves: #1329233 +--- + man/journal-remote.conf.xml | 7 +++++++ + src/journal-remote/journal-remote.c | 1 + + src/journal-remote/journal-remote.conf.in | 1 + + 3 files changed, 9 insertions(+) + +diff --git a/man/journal-remote.conf.xml b/man/journal-remote.conf.xml +index a7b2227..9a385c7 100644 +--- a/man/journal-remote.conf.xml ++++ b/man/journal-remote.conf.xml +@@ -72,6 +72,13 @@ + [Remote] section: + + ++ ++ Seal= ++ ++ Periodically sign the data in the journal using Forward Secure Sealing. ++ ++ ++ + + + SplitMode= +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index b7cc6d7..9c515f9 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -1174,6 +1174,7 @@ static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode, + + static int parse_config(void) { + const ConfigTableItem items[] = { ++ { "Remote", "Seal", config_parse_bool, 0, &arg_seal }, + { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode }, + { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key }, + { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert }, +diff --git a/src/journal-remote/journal-remote.conf.in b/src/journal-remote/journal-remote.conf.in +index 3e32f34..7122d63 100644 +--- a/src/journal-remote/journal-remote.conf.in ++++ b/src/journal-remote/journal-remote.conf.in +@@ -1,4 +1,5 @@ + [Remote] ++# Seal=false + # SplitMode=host + # ServerKeyFile=@CERTIFICATEROOT@/private/journal-remote.pem + # ServerCertificateFile=@CERTIFICATEROOT@/certs/journal-remote.pem diff --git a/SOURCES/0309-tests-fix-make-check-failure.patch b/SOURCES/0309-tests-fix-make-check-failure.patch new file mode 100644 index 0000000..4eae4c3 --- /dev/null +++ b/SOURCES/0309-tests-fix-make-check-failure.patch @@ -0,0 +1,26 @@ +From 44eb30c33deb46f92d2c67e78a5fb7aa6b21d145 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 28 Apr 2016 16:04:52 +0200 +Subject: [PATCH] tests: fix make check failure + +Don't call abort() on success. Actually rm_rf_dangerous() returns 0 if +all went well. + +Related: #1159308 +--- + src/test/test-install-root.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c +index 89d91d3..667c374 100644 +--- a/src/test/test-install-root.c ++++ b/src/test/test-install-root.c +@@ -657,7 +657,7 @@ int main(int argc, char *argv[]) { + test_indirect(root); + test_preset_and_list(root); + +- assert_se(rm_rf_dangerous(root, false, true, false)); ++ assert_se(rm_rf_dangerous(root, false, true, false) == 0); + + return 0; + } diff --git a/SOURCES/0310-device-make-sure-to-not-ignore-re-plugged-device.patch b/SOURCES/0310-device-make-sure-to-not-ignore-re-plugged-device.patch new file mode 100644 index 0000000..0bc39b6 --- /dev/null +++ b/SOURCES/0310-device-make-sure-to-not-ignore-re-plugged-device.patch @@ -0,0 +1,65 @@ +From 45ff3d79f079c73c73209940cf6eaa0ea0a95708 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Fri, 22 Jan 2016 07:18:19 +0100 +Subject: [PATCH] device: make sure to not ignore re-plugged device + +systemd automatically mounts device unless 'noauto' is part of the +mount options. This can happen during boot if the device is plugged at +that time or later when the system is already running (the latter case +is not documented AFAICS). + +After the systemd booted, I plugged my USB device which had an entry +in /etc/fstab with the default options and systemd automatically +mounted it. + +However I noticed that if I unplugged and re-plugged the device the +automatic mounting of the device didn't work anymore: systemd didn't +notice that the device was re-plugged. + +This was due to the device unit which was not recycled by the GC +during the unplug event because in the case of automounting, the mount +unit still referenced it. When the device was re-plugged, the old +device unit was reused but it still had the old sysfs path (amongst +other useful information). + +Systemd was confused by the stalled sysfs path and decided to ignore +the plug event. + +This patch fixes this issue by simply not doing the sanity checking on +the sysfs path if the device is in unplugged state. + +Cherry-picked from: ac9d396b2abbae4e7ab84f7b556f70681b66236b +Resolves: #1332606 +--- + src/core/device.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/src/core/device.c b/src/core/device.c +index 1995e3c..fc73e26 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -314,11 +314,19 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa + + u = manager_get_unit(m, e); + +- if (u && +- DEVICE(u)->sysfs && +- !path_equal(DEVICE(u)->sysfs, sysfs)) { +- log_unit_debug(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); +- return -EEXIST; ++ /* The device unit can still be present even if the device was ++ * unplugged: a mount unit can reference it hence preventing ++ * the GC to have garbaged it. That's desired since the device ++ * unit may have a dependency on the mount unit which was ++ * added during the loading of the later. */ ++ if (u && DEVICE(u)->state == DEVICE_PLUGGED) { ++ /* This unit is in plugged state: we're sure it's ++ * attached to a device. */ ++ if (!path_equal(DEVICE(u)->sysfs, sysfs)) { ++ log_unit_debug(u->id, "Dev %s appeared twice with different sysfs paths %s and %s", ++ e, DEVICE(u)->sysfs, sysfs); ++ return -EEXIST; ++ } + } + + if (!u) { diff --git a/SOURCES/0311-device-Ensure-we-have-sysfs-path-before-comparing.patch b/SOURCES/0311-device-Ensure-we-have-sysfs-path-before-comparing.patch new file mode 100644 index 0000000..f695fad --- /dev/null +++ b/SOURCES/0311-device-Ensure-we-have-sysfs-path-before-comparing.patch @@ -0,0 +1,33 @@ +From ce046ce7f8545d174dc8ecb45b27c2049d96f935 Mon Sep 17 00:00:00 2001 +From: Colin Guthrie +Date: Mon, 14 Mar 2016 09:42:07 +0000 +Subject: [PATCH] device: Ensure we have sysfs path before comparing. + +In some cases we do not have a udev device when setting up a unit +(certainly the code gracefully handles this). However, we do +then go on to compare the path via path_equal which will assert +if a null value is passed in. + +See https://bugs.mageia.org/show_bug.cgi?id=17766 + +Not sure if this is the correct fix, but it avoids the crash + +Cherry-picked from: 5e1558f4a09e596561c9168384f2258e7c0718a1 +Resolves: #1332606 +--- + src/core/device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/device.c b/src/core/device.c +index fc73e26..bdc8466 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -319,7 +319,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa + * the GC to have garbaged it. That's desired since the device + * unit may have a dependency on the mount unit which was + * added during the loading of the later. */ +- if (u && DEVICE(u)->state == DEVICE_PLUGGED) { ++ if (sysfs && u && DEVICE(u)->state == DEVICE_PLUGGED) { + /* This unit is in plugged state: we're sure it's + * attached to a device. */ + if (!path_equal(DEVICE(u)->sysfs, sysfs)) { diff --git a/SOURCES/0312-core-fix-memory-leak-on-set-default-enable-disable-e.patch b/SOURCES/0312-core-fix-memory-leak-on-set-default-enable-disable-e.patch new file mode 100644 index 0000000..958c0d7 --- /dev/null +++ b/SOURCES/0312-core-fix-memory-leak-on-set-default-enable-disable-e.patch @@ -0,0 +1,23 @@ +From 805365980feaec626e80c6514b46a6e4de319b77 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 29 Apr 2016 09:40:23 +0200 +Subject: [PATCH] core: fix memory leak on set-default, enable, disable etc + +Cherry-picked from: 24f412ca4150b490648ab8de45c6eda5bd697fd8 +Related: #1331667 +--- + src/core/dbus-manager.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index faa124d..1a5525e 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1621,6 +1621,7 @@ static int reply_unit_file_changes_and_free( + if (r < 0) + goto fail; + ++ unit_file_changes_free(changes, n_changes); + return sd_bus_send(bus, reply, NULL); + + fail: diff --git a/SOURCES/0313-nspawn-fix-minor-memory-leak.patch b/SOURCES/0313-nspawn-fix-minor-memory-leak.patch new file mode 100644 index 0000000..12818bc --- /dev/null +++ b/SOURCES/0313-nspawn-fix-minor-memory-leak.patch @@ -0,0 +1,26 @@ +From 94f823629031f8849c8dc001d56a2c057531f0f2 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 28 Oct 2015 18:22:23 +0100 +Subject: [PATCH] nspawn: fix minor memory leak + +When rebooting nspawn containers about 400 times we'd otherwise hit the +fd limit and refuse further reboots. + +Cherry-picked from: 3c747da38ca2f0642b4811812f6e2e2e1449a622 +Related: #1331667 +--- + src/shared/ptyfwd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c +index 31274a1..88b3f4e 100644 +--- a/src/shared/ptyfwd.c ++++ b/src/shared/ptyfwd.c +@@ -388,6 +388,7 @@ PTYForward *pty_forward_free(PTYForward *f) { + sd_event_source_unref(f->stdin_event_source); + sd_event_source_unref(f->stdout_event_source); + sd_event_source_unref(f->master_event_source); ++ sd_event_source_unref(f->sigwinch_event_source); + sd_event_unref(f->event); + + if (f->saved_stdout) diff --git a/SOURCES/0314-basic-fix-error-memleak-in-socket-util.patch b/SOURCES/0314-basic-fix-error-memleak-in-socket-util.patch new file mode 100644 index 0000000..fcd43b4 --- /dev/null +++ b/SOURCES/0314-basic-fix-error-memleak-in-socket-util.patch @@ -0,0 +1,28 @@ +From 605a35e6e8dcb2518a1fa8f92fb5fb00a0419345 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Fri, 29 Apr 2016 12:13:06 +0200 +Subject: [PATCH] basic: fix error/memleak in socket-util + +Probably a typo, checking 'ret' instead of the return value 'p'. This +might cause the function to return failure, even though it succeeded. +Furthermore, it might leak resources. + +Cherry-picked from: 0810bc568ace619b16e440805e93256730d45541 +Related: #1331667 +--- + src/shared/socket-util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index a4e26b1..407d0af 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -544,7 +544,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ + + } else { + p = strndup(sa->un.sun_path, sizeof(sa->un.sun_path)); +- if (!ret) ++ if (!p) + return -ENOMEM; + } + diff --git a/SOURCES/0315-core-fix-memory-leak-in-manager_run_generators.patch b/SOURCES/0315-core-fix-memory-leak-in-manager_run_generators.patch new file mode 100644 index 0000000..2e0202d --- /dev/null +++ b/SOURCES/0315-core-fix-memory-leak-in-manager_run_generators.patch @@ -0,0 +1,52 @@ +From fa5a3a16e94773baf1dce3881d5cfab556b87113 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Mon, 11 May 2015 23:30:38 -0300 +Subject: [PATCH] core: fix memory leak in manager_run_generators() + +If systemd is built with GCC address sanitizer or leak sanitizer +the following memory leak ocurs: + +May 12 02:02:46 linux.site systemd[326]: ================================================================= +May 12 02:02:46 linux.site systemd[326]: ==326==ERROR: LeakSanitizer: detected memory leaks +May 12 02:02:46 linux.site systemd[326]: Direct leak of 101 byte(s) in 3 object(s) allocated from: +May 12 02:02:46 linux.site systemd[326]: #0 0x7fd1f504993f in strdup (/usr/lib64/libasan.so.2+0x6293f) +May 12 02:02:46 linux.site systemd[326]: #1 0x55d6ffac5336 in strv_new_ap src/shared/strv.c:163 +May 12 02:02:46 linux.site systemd[326]: #2 0x55d6ffac56a9 in strv_new src/shared/strv.c:185 +May 12 02:02:46 linux.site systemd[326]: #3 0x55d6ffa80272 in generator_paths src/shared/path-lookup.c:223 +May 12 02:02:46 linux.site systemd[326]: #4 0x55d6ff9bdb0f in manager_run_generators src/core/manager.c:2828 +May 12 02:02:46 linux.site systemd[326]: #5 0x55d6ff9b1a10 in manager_startup src/core/manager.c:1121 +May 12 02:02:46 linux.site systemd[326]: #6 0x55d6ff9a78e3 in main src/core/main.c:1667 +May 12 02:02:46 linux.site systemd[326]: #7 0x7fd1f394e8c4 in __libc_start_main (/lib64/libc.so.6+0x208c4) +May 12 02:02:46 linux.site systemd[326]: Direct leak of 29 byte(s) in 1 object(s) allocated from: +May 12 02:02:46 linux.site systemd[326]: #0 0x7fd1f504993f in strdup (/usr/lib64/libasan.so.2+0x6293f) +May 12 02:02:46 linux.site systemd[326]: #1 0x55d6ffac5288 in strv_new_ap src/shared/strv.c:152 +May 12 02:02:46 linux.site systemd[326]: #2 0x55d6ffac56a9 in strv_new src/shared/strv.c:185 +May 12 02:02:46 linux.site systemd[326]: #3 0x55d6ffa80272 in generator_paths src/shared/path-lookup.c:223 +May 12 02:02:46 linux.site systemd[326]: #4 0x55d6ff9bdb0f in manager_run_generators src/core/manager.c:2828 +May 12 02:02:46 linux.site systemd[326]: #5 0x55d6ff9b1a10 in manager_startup src/core/manager.c:1121 +May 12 02:02:46 linux.site systemd[326]: #6 0x55d6ff9a78e3 in main src/core/main.c:1667 +May 12 02:02:46 linux.site systemd[326]: #7 0x7fd1f394e8c4 in __libc_start_main (/lib64/libc.so.6+0x208c4) +May 12 02:02:46 linux.site systemd[326]: SUMMARY: AddressSanitizer: 130 byte(s) leaked in 4 allocation(s). + +There is a leak due to the the use of cleanup_free instead +_cleanup_strv_free_ + +Cherry-picked from: f42348ace7feb2311593b8cf6c876856eecf256a +Related: #1331667 +--- + src/core/manager.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index bb50503..a1504bf 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -2827,7 +2827,7 @@ static void trim_generator_dir(Manager *m, char **generator) { + } + + static int manager_run_generators(Manager *m) { +- _cleanup_free_ char **paths = NULL; ++ _cleanup_strv_free_ char **paths = NULL; + const char *argv[5]; + char **path; + int r; diff --git a/SOURCES/0316-modules-load-fix-memory-leak.patch b/SOURCES/0316-modules-load-fix-memory-leak.patch new file mode 100644 index 0000000..32e483b --- /dev/null +++ b/SOURCES/0316-modules-load-fix-memory-leak.patch @@ -0,0 +1,41 @@ +From 3c3d3e3e040d980186fec05506018db2d24faa83 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Mon, 11 May 2015 15:37:47 -0300 +Subject: [PATCH] modules-load: fix memory leak + +================================================================= +==64281==ERROR: LeakSanitizer: detected memory leaks + +Direct leak of 32 byte(s) in 1 object(s) allocated from: + #0 0x7f623c961c4a in malloc (/usr/lib64/libasan.so.2+0x96c4a) + #1 0x5651f79ad34e in malloc_multiply (/home/crrodriguez/scm/systemd/systemd-modules-load+0x2134e) + #2 0x5651f79b02d6 in strjoin (/home/crrodriguez/scm/systemd/systemd-modules-load+0x242d6) + #3 0x5651f79be1f5 in files_add (/home/crrodriguez/scm/systemd/systemd-modules-load+0x321f5) + #4 0x5651f79be6a3 in conf_files_list_strv_internal (/home/crrodriguez/scm/systemd/systemd-modules-load+0x326a3) + #5 0x5651f79bea24 in conf_files_list_nulstr (/home/crrodriguez/scm/systemd/systemd-modules-load+0x32a24) + #6 0x5651f79ad01a in main (/home/crrodriguez/scm/systemd/systemd-modules-load+0x2101a) + #7 0x7f623c11586f in __libc_start_main (/lib64/libc.so.6+0x2086f) + +SUMMARY: AddressSanitizer: 32 byte(s) leaked in 1 allocation(s). + +This happens due to the wrong cleanup attribute is used (free vs strv_free) + +Cherry-picked from: 4df3277881cffcd3bc9a5238203d6af7e1fd960f +Related: #1331667 +--- + src/modules-load/modules-load.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c +index 5f67878..bab9246 100644 +--- a/src/modules-load/modules-load.c ++++ b/src/modules-load/modules-load.c +@@ -256,7 +256,7 @@ int main(int argc, char *argv[]) { + } + + } else { +- _cleanup_free_ char **files = NULL; ++ _cleanup_strv_free_ char **files = NULL; + char **fn, **i; + + STRV_FOREACH(i, arg_proc_cmdline_modules) { diff --git a/SOURCES/0317-core-fix-memory-leak-on-failed-preset-all.patch b/SOURCES/0317-core-fix-memory-leak-on-failed-preset-all.patch new file mode 100644 index 0000000..882253a --- /dev/null +++ b/SOURCES/0317-core-fix-memory-leak-on-failed-preset-all.patch @@ -0,0 +1,66 @@ +From 9d00fbb87c43e129e1ab29298afc86b7e8eed25c Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Mon, 18 Jan 2016 06:10:33 +0000 +Subject: [PATCH] core: fix memory leak on failed preset-all + +How to reproduce +$ systemctl set-default multi-user # https://github.com/systemd/systemd/issues/2298 +$ systemctl preset-all +Failed to execute operation: Too many levels of symbolic links + +$ systemctl poweroff + +Fixes: +==1== +==1== HEAP SUMMARY: +==1== in use at exit: 65,645 bytes in 7 blocks +==1== total heap usage: 40,539 allocs, 40,532 frees, 30,147,547 bytes allocated +==1== +==1== 109 (24 direct, 85 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 7 +==1== at 0x4C2BBCF: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +==1== by 0x4C2DE2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +==1== by 0x23DA71: unit_file_changes_add (install.c:233) +==1== by 0x23E45D: remove_marked_symlinks_fd (install.c:453) +==1== by 0x23E267: remove_marked_symlinks_fd (install.c:405) +==1== by 0x23E641: remove_marked_symlinks (install.c:494) +==1== by 0x243A91: execute_preset (install.c:2190) +==1== by 0x244343: unit_file_preset_all (install.c:2351) +==1== by 0x18AAA2: method_preset_all_unit_files (dbus-manager.c:1846) +==1== by 0x1D8157: method_callbacks_run (bus-objects.c:420) +==1== by 0x1DA9E9: object_find_and_run (bus-objects.c:1257) +==1== by 0x1DB02B: bus_process_object (bus-objects.c:1373) +==1== +==1== LEAK SUMMARY: +==1== definitely lost: 24 bytes in 1 blocks +==1== indirectly lost: 85 bytes in 1 blocks +==1== possibly lost: 0 bytes in 0 blocks +==1== still reachable: 65,536 bytes in 5 blocks +==1== suppressed: 0 bytes in 0 blocks +==1== Reachable blocks (those to which a pointer was found) are not shown. +==1== To see them, rerun with: --leak-check=full --show-leak-kinds=all +==1== +==1== For counts of detected and suppressed errors, rerun with: -v +==1== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) + +Cherry-picked from: c292c3af38c8c23e183f3e63ef492926cea64bab +Related: #1331667 +--- + src/core/dbus-manager.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 1a5525e..9eef290 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1875,8 +1875,10 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo + scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + + r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes); +- if (r < 0) ++ if (r < 0) { ++ unit_file_changes_free(changes, n_changes); + return r; ++ } + + return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes); + } diff --git a/SOURCES/0318-sd-bus-fix-memory-leak-in-test-bus-chat.patch b/SOURCES/0318-sd-bus-fix-memory-leak-in-test-bus-chat.patch new file mode 100644 index 0000000..1dc4f72 --- /dev/null +++ b/SOURCES/0318-sd-bus-fix-memory-leak-in-test-bus-chat.patch @@ -0,0 +1,37 @@ +From 68550741351080ab8458d54a6900b2b6ea1ef511 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cristian=20Rodr=C3=ADguez?= +Date: Sat, 9 May 2015 22:14:09 -0300 +Subject: [PATCH] sd-bus: fix memory leak in test-bus-chat + +Building with address sanitizer enabled on GCC 5.1.x a memory leak +is reported because we never close the bus, fix it by using +cleanup variable attribute. + +Cherry-picked from: 2f50a2d55bf0a8b5959a6864ae1b39e7e9e0ce08 +Related: #1331667 +--- + src/libsystemd/sd-bus/test-bus-chat.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c +index 8625ee6..a80aaae 100644 +--- a/src/libsystemd/sd-bus/test-bus-chat.c ++++ b/src/libsystemd/sd-bus/test-bus-chat.c +@@ -264,7 +264,7 @@ fail: + + static void* client1(void*p) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; +- sd_bus *bus = NULL; ++ _cleanup_bus_close_unref_ sd_bus *bus = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + const char *hello; + int r; +@@ -347,8 +347,6 @@ finish: + else + sd_bus_send(bus, q, NULL); + +- sd_bus_flush(bus); +- sd_bus_unref(bus); + } + + sd_bus_error_free(&error); diff --git a/SOURCES/0319-core-fix-memory-leak-in-transient-units.patch b/SOURCES/0319-core-fix-memory-leak-in-transient-units.patch new file mode 100644 index 0000000..9ef8b84 --- /dev/null +++ b/SOURCES/0319-core-fix-memory-leak-in-transient-units.patch @@ -0,0 +1,55 @@ +From c7d030b3f2b5969751872673e9082d0c10c031b5 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 15 Jan 2016 02:41:27 +0000 +Subject: [PATCH] core: fix memory leak in transient units + +Fixes: +==1== HEAP SUMMARY: +==1== in use at exit: 67,182 bytes in 91 blocks +==1== total heap usage: 70,485 allocs, 70,394 frees, 42,184,635 bytes +allocated +==1== +==1== 5,742 (696 direct, 5,046 indirect) bytes in 29 blocks are +definitely lost in loss record 4 of 7 +==1== at 0x4C2DD9F: realloc (in +/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +==1== by 0x21ADDD: realloc_multiply (alloc-util.h:67) +==1== by 0x21BFB0: strv_push (strv.c:448) +==1== by 0x21C245: strv_consume (strv.c:520) +==1== by 0x21C33C: strv_extend (strv.c:559) +==1== by 0x278AD7: unit_write_drop_in (unit.c:3352) +==1== by 0x278EEB: unit_write_drop_in_private (unit.c:3403) +==1== by 0x190C21: bus_service_set_transient_property +(dbus-service.c:254) +==1== by 0x190DBC: bus_service_set_property (dbus-service.c:284) +==1== by 0x18F00E: bus_unit_set_properties (dbus-unit.c:1226) +==1== by 0x186F6A: transient_unit_from_message (dbus-manager.c:683) +==1== by 0x1872B7: method_start_transient_unit (dbus-manager.c:763) +==1== +==1== LEAK SUMMARY: +==1== definitely lost: 696 bytes in 29 blocks +==1== indirectly lost: 5,046 bytes in 58 blocks +==1== possibly lost: 0 bytes in 0 blocks +==1== still reachable: 61,440 bytes in 4 blocks +==1== suppressed: 0 bytes in 0 blocks + +Cherry-picked from: af4fbf3c1fdd4196f7a325602daaa846fe5f3012 +Related: #1331667 +--- + src/core/load-dropin.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c +index 8be1900..42cf005 100644 +--- a/src/core/load-dropin.c ++++ b/src/core/load-dropin.c +@@ -68,6 +68,9 @@ int unit_load_dropin(Unit *u) { + } + } + ++ strv_free(u->dropin_paths); ++ u->dropin_paths = NULL; ++ + r = unit_find_dropin_paths(u, &u->dropin_paths); + if (r <= 0) + return 0; diff --git a/SOURCES/0320-bus-fix-leak-in-error-path.patch b/SOURCES/0320-bus-fix-leak-in-error-path.patch new file mode 100644 index 0000000..834a358 --- /dev/null +++ b/SOURCES/0320-bus-fix-leak-in-error-path.patch @@ -0,0 +1,52 @@ +From 69aaf3c41923fafd9616b1bbec51fa6bcb23b886 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 7 Mar 2015 15:05:50 -0500 +Subject: [PATCH] bus: fix leak in error path + +CID #1271349. + +Cherry-picked from: bcf88fc3f14867f1cabc911c27b661d738281df0 +Related: #1331667 +--- + src/libsystemd/sd-bus/bus-message.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c +index 2959303..c8402a2 100644 +--- a/src/libsystemd/sd-bus/bus-message.c ++++ b/src/libsystemd/sd-bus/bus-message.c +@@ -441,7 +441,7 @@ int bus_message_from_header( + size_t extra, + sd_bus_message **ret) { + +- sd_bus_message *m; ++ _cleanup_free_ sd_bus_message *m = NULL; + struct bus_header *h; + size_t a, label_sz; + +@@ -460,15 +460,13 @@ int bus_message_from_header( + return -EBADMSG; + + h = header; +- if (h->version != 1 && +- h->version != 2) ++ if (!IN_SET(h->version, 1, 2)) + return -EBADMSG; + + if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID) + return -EBADMSG; + +- if (h->endian != BUS_LITTLE_ENDIAN && +- h->endian != BUS_BIG_ENDIAN) ++ if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN)) + return -EBADMSG; + + /* Note that we are happy with unknown flags in the flags header! */ +@@ -557,6 +555,7 @@ int bus_message_from_header( + + m->bus = sd_bus_ref(bus); + *ret = m; ++ m = NULL; + + return 0; + } diff --git a/SOURCES/0321-shared-logs-show-fix-memleak-in-add_matches_for_unit.patch b/SOURCES/0321-shared-logs-show-fix-memleak-in-add_matches_for_unit.patch new file mode 100644 index 0000000..54d207e --- /dev/null +++ b/SOURCES/0321-shared-logs-show-fix-memleak-in-add_matches_for_unit.patch @@ -0,0 +1,24 @@ +From c95edddeb70a48202a0baf7b71450be87d2d921c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 12 Apr 2016 23:36:37 -0400 +Subject: [PATCH] shared/logs-show: fix memleak in add_matches_for_unit + +Cherry-picked from: 42fbdf45864b46f3eb62a3738b81e687685eb9bd +Related: #1331667 +--- + src/shared/logs-show.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c +index c249505..8c37411 100644 +--- a/src/shared/logs-show.c ++++ b/src/shared/logs-show.c +@@ -1060,7 +1060,7 @@ int add_matches_for_unit(sd_journal *j, const char *unit) { + ); + + if (r == 0 && endswith(unit, ".slice")) { +- char *m5 = strappend("_SYSTEMD_SLICE=", unit); ++ const char *m5 = strjoina("_SYSTEMD_SLICE=", unit); + + /* Show all messages belonging to a slice */ + (void)( diff --git a/SOURCES/0322-logind-introduce-LockedHint-and-SetLockedHint-3238.patch b/SOURCES/0322-logind-introduce-LockedHint-and-SetLockedHint-3238.patch new file mode 100644 index 0000000..bdf69ca --- /dev/null +++ b/SOURCES/0322-logind-introduce-LockedHint-and-SetLockedHint-3238.patch @@ -0,0 +1,164 @@ +From 75131b469fa9e1e2e3cb623fa1f3d36cba36af78 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Wed, 11 May 2016 19:34:13 +0200 +Subject: [PATCH] logind: introduce LockedHint and SetLockedHint (#3238) + +Desktop environments can keep this property up to date to allow +applications to easily track session's Lock status. + +Cherry-picked from: 42d35e1301928d08dd32ec51f0205252ae658ba5 +Resolves: #1335499 +--- + src/login/logind-session-dbus.c | 50 +++++++++++++++++++++++++++++++++++ + src/login/logind-session.c | 17 ++++++++++++ + src/login/logind-session.h | 4 +++ + src/login/org.freedesktop.login1.conf | 4 +++ + 4 files changed, 75 insertions(+) + +diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c +index 4e7edef..75b7186 100644 +--- a/src/login/logind-session-dbus.c ++++ b/src/login/logind-session-dbus.c +@@ -180,6 +180,24 @@ static int property_get_idle_since_hint( + return sd_bus_message_append(reply, "t", u); + } + ++static int property_get_locked_hint( ++ sd_bus *bus, ++ const char *path, ++ const char *interface, ++ const char *property, ++ sd_bus_message *reply, ++ void *userdata, ++ sd_bus_error *error) { ++ ++ Session *s = userdata; ++ ++ assert(bus); ++ assert(reply); ++ assert(s); ++ ++ return sd_bus_message_append(reply, "b", session_get_locked_hint(s) > 0); ++} ++ + static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + int r; +@@ -255,6 +273,36 @@ static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *user + return sd_bus_reply_method_return(message, NULL); + } + ++static int method_set_locked_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { ++ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; ++ Session *s = userdata; ++ uid_t uid; ++ int r, b; ++ ++ assert(bus); ++ assert(message); ++ assert(s); ++ ++ r = sd_bus_message_read(message, "b", &b); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); ++ if (r < 0) ++ return r; ++ ++ r = sd_bus_creds_get_euid(creds, &uid); ++ if (r < 0) ++ return r; ++ ++ if (uid != 0 && uid != s->user->uid) ++ return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint"); ++ ++ session_set_locked_hint(s, b); ++ ++ return sd_bus_reply_method_return(message, NULL); ++} ++ + static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Session *s = userdata; + const char *swho; +@@ -455,6 +503,7 @@ const sd_bus_vtable session_vtable[] = { + SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), ++ SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + + SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), + SD_BUS_METHOD("Activate", NULL, NULL, method_activate, SD_BUS_VTABLE_UNPRIVILEGED), +@@ -462,6 +511,7 @@ const sd_bus_vtable session_vtable[] = { + SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0), + SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("Kill", "si", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)), ++ SD_BUS_METHOD("SetLockedHint", "b", NULL, method_set_locked_hint, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED), +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index d2e7b40..dc24539 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -843,6 +843,23 @@ void session_set_idle_hint(Session *s, bool b) { + manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL); + } + ++int session_get_locked_hint(Session *s) { ++ assert(s); ++ ++ return s->locked_hint; ++} ++ ++void session_set_locked_hint(Session *s, bool b) { ++ assert(s); ++ ++ if (s->locked_hint == b) ++ return; ++ ++ s->locked_hint = b; ++ ++ session_send_changed(s, "LockedHint", NULL); ++} ++ + static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Session *s = userdata; + +diff --git a/src/login/logind-session.h b/src/login/logind-session.h +index a007fb5..5002b68 100644 +--- a/src/login/logind-session.h ++++ b/src/login/logind-session.h +@@ -111,6 +111,8 @@ struct Session { + bool idle_hint; + dual_timestamp idle_hint_timestamp; + ++ bool locked_hint; ++ + bool in_gc_queue:1; + bool started:1; + bool stopping:1; +@@ -137,6 +139,8 @@ int session_activate(Session *s); + bool session_is_active(Session *s); + int session_get_idle_hint(Session *s, dual_timestamp *t); + void session_set_idle_hint(Session *s, bool b); ++int session_get_locked_hint(Session *s); ++void session_set_locked_hint(Session *s, bool b); + int session_create_fifo(Session *s); + int session_start(Session *s); + int session_stop(Session *s, bool force); +diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf +index 1318328..dc7e0be 100644 +--- a/src/login/org.freedesktop.login1.conf ++++ b/src/login/org.freedesktop.login1.conf +@@ -162,6 +162,10 @@ + + ++ ++ + + +Date: Wed, 6 Apr 2016 15:39:09 +0200 +Subject: [PATCH] import: use the old curl api + +libcurl in rhel does not have CURLOPT_XFERINFO* symbols, so lets use the +old interface. + +RHEL-only +Resolves: #1284974 +--- + src/import/import-job.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/import/import-job.c b/src/import/import-job.c +index 8094865..5f9cfd3 100644 +--- a/src/import/import-job.c ++++ b/src/import/import-job.c +@@ -587,7 +587,7 @@ fail: + return 0; + } + +-static int import_job_progress_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { ++static int import_job_progress_callback(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow) { + ImportJob *j = userdata; + unsigned percent; + usec_t n; +@@ -714,10 +714,10 @@ int import_job_begin(ImportJob *j) { + if (curl_easy_setopt(j->curl, CURLOPT_HEADERDATA, j) != CURLE_OK) + return -EIO; + +- if (curl_easy_setopt(j->curl, CURLOPT_XFERINFOFUNCTION, import_job_progress_callback) != CURLE_OK) ++ if (curl_easy_setopt(j->curl, CURLOPT_PROGRESSFUNCTION, import_job_progress_callback) != CURLE_OK) + return -EIO; + +- if (curl_easy_setopt(j->curl, CURLOPT_XFERINFODATA, j) != CURLE_OK) ++ if (curl_easy_setopt(j->curl, CURLOPT_PROGRESSDATA, j) != CURLE_OK) + return -EIO; + + if (curl_easy_setopt(j->curl, CURLOPT_NOPROGRESS, 0) != CURLE_OK) diff --git a/SOURCES/0324-importd-drop-dkr-support.patch b/SOURCES/0324-importd-drop-dkr-support.patch new file mode 100644 index 0000000..e6c1d55 --- /dev/null +++ b/SOURCES/0324-importd-drop-dkr-support.patch @@ -0,0 +1,1694 @@ +From b4bfb025f7ab0878e8e7e980dbad5b0a5bed1555 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 10 Dec 2015 12:40:04 +0100 +Subject: [PATCH] importd: drop dkr support + +The current code is not compatible with current dkr protocols anyway, +and dkr has a different focus ("microservices") than nspawn anyway +("whole machine containers"), hence drop support for it, we cannot +reasonably keep this up to date, and it creates the impression we'd +actually care for the microservices usecase. + +Cherry-picked from: b43d75c +Related: #1284974 +--- + Makefile.am | 2 - + TODO | 4 - + configure.ac | 9 - + man/machinectl.xml | 58 --- + src/import/import-dkr.c | 891 -------------------------------- + src/import/import-dkr.h | 36 -- + src/import/importd.c | 111 +--- + src/import/org.freedesktop.import1.conf | 4 - + src/import/pull.c | 119 +---- + src/machine/machinectl.c | 90 +--- + src/shared/import-util.c | 31 -- + src/shared/import-util.h | 4 - + 12 files changed, 5 insertions(+), 1354 deletions(-) + delete mode 100644 src/import/import-dkr.c + delete mode 100644 src/import/import-dkr.h + +diff --git a/Makefile.am b/Makefile.am +index 3a09e0a..b0a34b2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5369,8 +5369,6 @@ systemd_pull_SOURCES = \ + src/import/import-raw.h \ + src/import/import-tar.c \ + src/import/import-tar.h \ +- src/import/import-dkr.c \ +- src/import/import-dkr.h \ + src/import/import-job.c \ + src/import/import-job.h \ + src/import/import-common.c \ +diff --git a/TODO b/TODO +index 90b2c4b..d96d2bf 100644 +--- a/TODO ++++ b/TODO +@@ -126,10 +126,6 @@ Features: + + * rework journald sigbus stuff to use mutex + +-* import-dkr: support tarsum checksum verification, if it becomes reality one day... +- +-* import-dkr: convert json bits to nspawn configuration +- + * import: support import from local files, and export to local files + + * core/cgroup: support net_cls modules, and support automatically allocating class ids, then add support for making firewall changes depending on it, to implement a per-service firewall +diff --git a/configure.ac b/configure.ac +index 9103f9b..2734368 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1389,14 +1389,6 @@ AC_ARG_ENABLE([split-usr], + enable_split_usr=no + ])]) + +-AC_ARG_WITH([dkr-index-url], +- [AS_HELP_STRING([--dkr-index-url=URL], [Specify the default index URL to use for image downloads])], +- [DEFAULT_DKR_INDEX_URL="\"$withval\""], +- [DEFAULT_DKR_INDEX_URL="NULL"]) +- +-AC_DEFINE_UNQUOTED(DEFAULT_DKR_INDEX_URL, [$DEFAULT_DKR_INDEX_URL], [Default index URL to use for image downloads]) +-AC_SUBST(DEFAULT_DKR_INDEX_URL) +- + AS_IF([test "x${enable_split_usr}" = "xyes"], [ + AC_DEFINE(HAVE_SPLIT_USR, 1, [Define if /bin, /sbin aren't symlinks into /usr]) + ]) +@@ -1564,7 +1556,6 @@ AC_MSG_RESULT([ + Maximum System UID: ${SYSTEM_UID_MAX} + Maximum System GID: ${SYSTEM_GID_MAX} + Certificate root: ${CERTIFICATEROOT} +- Default dkr Index ${DEFAULT_DKR_INDEX_URL} + + CFLAGS: ${OUR_CFLAGS} ${CFLAGS} + CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} +diff --git a/man/machinectl.xml b/man/machinectl.xml +index 640cb8b..b0a7f2a 100644 +--- a/man/machinectl.xml ++++ b/man/machinectl.xml +@@ -204,16 +204,6 @@ + image. + + +- +- +- +- Specifies the index server to use for +- downloading dkr images with the +- pull-dkr. Takes a +- http://, https:// +- URL. +- +- + + + +@@ -603,42 +593,6 @@ + + + +- pull-dkr REMOTE [NAME] +- +- Downloads a dkr container +- image and makes it available locally. The remote name refers +- to a dkr container name. If omitted, the +- local machine name is derived from the dkr +- container name. +- +- Image verification is not available for +- dkr containers, and thus +- must always be specified with +- this command. +- +- This command downloads all (missing) layers for the +- specified container and places them in read-only subvolumes in +- /var/lib/machines/. A writable snapshot +- of the newest layer is then created under the specified local +- machine name. To omit creation of this writable snapshot, pass +- - as local machine name. +- +- The read-only layer subvolumes are prefixed with +- .dkr-, and thus now shown by +- list-images, unless +- is passed. +- +- To specify the dkr index server to +- use for looking up the specified container, use +- . +- +- Note that pressing C-c during execution of this command +- will not abort the download. Use +- cancel-transfer, described +- below. +- +- +- + list-transfers + + Shows a list of container or VM image +@@ -728,18 +682,6 @@ + the machine started as system service. With the last command a + login prompt into the container is requested. + +- +- +- Download a Fedora <literal>dkr</literal> image +- +- # machinectl pull-dkr --verify=no mattdm/fedora +-# systemd-nspawn -M fedora +- +- Downloads a dkr image and opens a shell +- in it. Note that the specified download command might require an +- index server to be specified with the +- --dkr-index-url=. +- + + + +diff --git a/src/import/import-dkr.c b/src/import/import-dkr.c +deleted file mode 100644 +index fb72f6c..0000000 +--- a/src/import/import-dkr.c ++++ /dev/null +@@ -1,891 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2014 Lennart Poettering +- +- 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 . +-***/ +- +-#include +-#include +- +-#include "sd-daemon.h" +-#include "json.h" +-#include "strv.h" +-#include "btrfs-util.h" +-#include "utf8.h" +-#include "mkdir.h" +-#include "import-util.h" +-#include "curl-util.h" +-#include "aufs-util.h" +-#include "import-job.h" +-#include "import-common.h" +-#include "import-dkr.h" +- +-typedef enum DkrProgress { +- DKR_SEARCHING, +- DKR_RESOLVING, +- DKR_METADATA, +- DKR_DOWNLOADING, +- DKR_COPYING, +-} DkrProgress; +- +-struct DkrImport { +- sd_event *event; +- CurlGlue *glue; +- +- char *index_url; +- char *image_root; +- +- ImportJob *images_job; +- ImportJob *tags_job; +- ImportJob *ancestry_job; +- ImportJob *json_job; +- ImportJob *layer_job; +- +- char *name; +- char *tag; +- char *id; +- +- char *response_token; +- char **response_registries; +- +- char **ancestry; +- unsigned n_ancestry; +- unsigned current_ancestry; +- +- DkrImportFinished on_finished; +- void *userdata; +- +- char *local; +- bool force_local; +- +- char *temp_path; +- char *final_path; +- +- pid_t tar_pid; +-}; +- +-#define PROTOCOL_PREFIX "https://" +- +-#define HEADER_TOKEN "X-Do" /* the HTTP header for the auth token */ "cker-Token:" +-#define HEADER_REGISTRY "X-Do" /*the HTTP header for the registry */ "cker-Endpoints:" +- +-#define LAYERS_MAX 2048 +- +-static void dkr_import_job_on_finished(ImportJob *j); +- +-DkrImport* dkr_import_unref(DkrImport *i) { +- if (!i) +- return NULL; +- +- if (i->tar_pid > 1) { +- (void) kill_and_sigcont(i->tar_pid, SIGKILL); +- (void) wait_for_terminate(i->tar_pid, NULL); +- } +- +- import_job_unref(i->images_job); +- import_job_unref(i->tags_job); +- import_job_unref(i->ancestry_job); +- import_job_unref(i->json_job); +- import_job_unref(i->layer_job); +- +- curl_glue_unref(i->glue); +- sd_event_unref(i->event); +- +- if (i->temp_path) { +- (void) btrfs_subvol_remove(i->temp_path); +- (void) rm_rf_dangerous(i->temp_path, false, true, false); +- free(i->temp_path); +- } +- +- free(i->name); +- free(i->tag); +- free(i->id); +- free(i->response_token); +- free(i->response_registries); +- strv_free(i->ancestry); +- free(i->final_path); +- free(i->index_url); +- free(i->image_root); +- free(i->local); +- free(i); +- +- return NULL; +-} +- +-int dkr_import_new( +- DkrImport **ret, +- sd_event *event, +- const char *index_url, +- const char *image_root, +- DkrImportFinished on_finished, +- void *userdata) { +- +- _cleanup_(dkr_import_unrefp) DkrImport *i = NULL; +- char *e; +- int r; +- +- assert(ret); +- assert(index_url); +- +- if (!http_url_is_valid(index_url)) +- return -EINVAL; +- +- i = new0(DkrImport, 1); +- if (!i) +- return -ENOMEM; +- +- i->on_finished = on_finished; +- i->userdata = userdata; +- +- i->image_root = strdup(image_root ?: "/var/lib/machines"); +- if (!i->image_root) +- return -ENOMEM; +- +- i->index_url = strdup(index_url); +- if (!i->index_url) +- return -ENOMEM; +- +- e = endswith(i->index_url, "/"); +- if (e) +- *e = 0; +- +- if (event) +- i->event = sd_event_ref(event); +- else { +- r = sd_event_default(&i->event); +- if (r < 0) +- return r; +- } +- +- r = curl_glue_new(&i->glue, i->event); +- if (r < 0) +- return r; +- +- i->glue->on_finished = import_job_curl_on_finished; +- i->glue->userdata = i; +- +- *ret = i; +- i = NULL; +- +- return 0; +-} +- +-static void dkr_import_report_progress(DkrImport *i, DkrProgress p) { +- unsigned percent; +- +- assert(i); +- +- switch (p) { +- +- case DKR_SEARCHING: +- percent = 0; +- if (i->images_job) +- percent += i->images_job->progress_percent * 5 / 100; +- break; +- +- case DKR_RESOLVING: +- percent = 5; +- if (i->tags_job) +- percent += i->tags_job->progress_percent * 5 / 100; +- break; +- +- case DKR_METADATA: +- percent = 10; +- if (i->ancestry_job) +- percent += i->ancestry_job->progress_percent * 5 / 100; +- if (i->json_job) +- percent += i->json_job->progress_percent * 5 / 100; +- break; +- +- case DKR_DOWNLOADING: +- percent = 20; +- percent += 75 * i->current_ancestry / MAX(1U, i->n_ancestry); +- if (i->layer_job) +- percent += i->layer_job->progress_percent * 75 / MAX(1U, i->n_ancestry) / 100; +- +- break; +- +- case DKR_COPYING: +- percent = 95; +- break; +- +- default: +- assert_not_reached("Unknown progress state"); +- } +- +- sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); +- log_debug("Combined progress %u%%", percent); +-} +- +-static int parse_id(const void *payload, size_t size, char **ret) { +- _cleanup_free_ char *buf = NULL, *id = NULL, *other = NULL; +- union json_value v = {}; +- void *json_state = NULL; +- const char *p; +- int t; +- +- assert(payload); +- assert(ret); +- +- if (size <= 0) +- return -EBADMSG; +- +- if (memchr(payload, 0, size)) +- return -EBADMSG; +- +- buf = strndup(payload, size); +- if (!buf) +- return -ENOMEM; +- +- p = buf; +- t = json_tokenize(&p, &id, &v, &json_state, NULL); +- if (t < 0) +- return t; +- if (t != JSON_STRING) +- return -EBADMSG; +- +- t = json_tokenize(&p, &other, &v, &json_state, NULL); +- if (t < 0) +- return t; +- if (t != JSON_END) +- return -EBADMSG; +- +- if (!dkr_id_is_valid(id)) +- return -EBADMSG; +- +- *ret = id; +- id = NULL; +- +- return 0; +-} +- +-static int parse_ancestry(const void *payload, size_t size, char ***ret) { +- _cleanup_free_ char *buf = NULL; +- void *json_state = NULL; +- const char *p; +- enum { +- STATE_BEGIN, +- STATE_ITEM, +- STATE_COMMA, +- STATE_END, +- } state = STATE_BEGIN; +- _cleanup_strv_free_ char **l = NULL; +- size_t n = 0, allocated = 0; +- +- if (size <= 0) +- return -EBADMSG; +- +- if (memchr(payload, 0, size)) +- return -EBADMSG; +- +- buf = strndup(payload, size); +- if (!buf) +- return -ENOMEM; +- +- p = buf; +- for (;;) { +- _cleanup_free_ char *str; +- union json_value v = {}; +- int t; +- +- t = json_tokenize(&p, &str, &v, &json_state, NULL); +- if (t < 0) +- return t; +- +- switch (state) { +- +- case STATE_BEGIN: +- if (t == JSON_ARRAY_OPEN) +- state = STATE_ITEM; +- else +- return -EBADMSG; +- +- break; +- +- case STATE_ITEM: +- if (t == JSON_STRING) { +- if (!dkr_id_is_valid(str)) +- return -EBADMSG; +- +- if (n+1 > LAYERS_MAX) +- return -EFBIG; +- +- if (!GREEDY_REALLOC(l, allocated, n + 2)) +- return -ENOMEM; +- +- l[n++] = str; +- str = NULL; +- l[n] = NULL; +- +- state = STATE_COMMA; +- +- } else if (t == JSON_ARRAY_CLOSE) +- state = STATE_END; +- else +- return -EBADMSG; +- +- break; +- +- case STATE_COMMA: +- if (t == JSON_COMMA) +- state = STATE_ITEM; +- else if (t == JSON_ARRAY_CLOSE) +- state = STATE_END; +- else +- return -EBADMSG; +- break; +- +- case STATE_END: +- if (t == JSON_END) { +- +- if (strv_isempty(l)) +- return -EBADMSG; +- +- if (!strv_is_uniq(l)) +- return -EBADMSG; +- +- l = strv_reverse(l); +- +- *ret = l; +- l = NULL; +- return 0; +- } else +- return -EBADMSG; +- } +- +- } +-} +- +-static const char *dkr_import_current_layer(DkrImport *i) { +- assert(i); +- +- if (strv_isempty(i->ancestry)) +- return NULL; +- +- return i->ancestry[i->current_ancestry]; +-} +- +-static const char *dkr_import_current_base_layer(DkrImport *i) { +- assert(i); +- +- if (strv_isempty(i->ancestry)) +- return NULL; +- +- if (i->current_ancestry <= 0) +- return NULL; +- +- return i->ancestry[i->current_ancestry-1]; +-} +- +-static int dkr_import_add_token(DkrImport *i, ImportJob *j) { +- const char *t; +- +- assert(i); +- assert(j); +- +- if (i->response_token) +- t = strjoina("Authorization: Token ", i->response_token); +- else +- t = HEADER_TOKEN " true"; +- +- j->request_header = curl_slist_new("Accept: application/json", t, NULL); +- if (!j->request_header) +- return -ENOMEM; +- +- return 0; +-} +- +-static bool dkr_import_is_done(DkrImport *i) { +- assert(i); +- assert(i->images_job); +- +- if (i->images_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (!i->tags_job || i->tags_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (!i->ancestry_job || i->ancestry_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (!i->json_job || i->json_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (i->layer_job && i->layer_job->state != IMPORT_JOB_DONE) +- return false; +- +- if (dkr_import_current_layer(i)) +- return false; +- +- return true; +-} +- +-static int dkr_import_make_local_copy(DkrImport *i) { +- int r; +- +- assert(i); +- +- if (!i->local) +- return 0; +- +- if (!i->final_path) { +- i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL); +- if (!i->final_path) +- return log_oom(); +- } +- +- r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local); +- if (r < 0) +- return r; +- +- return 0; +-} +- +-static int dkr_import_job_on_open_disk(ImportJob *j) { +- const char *base; +- DkrImport *i; +- int r; +- +- assert(j); +- assert(j->userdata); +- +- i = j->userdata; +- assert(i->layer_job == j); +- assert(i->final_path); +- assert(!i->temp_path); +- assert(i->tar_pid <= 0); +- +- r = tempfn_random(i->final_path, &i->temp_path); +- if (r < 0) +- return log_oom(); +- +- mkdir_parents_label(i->temp_path, 0700); +- +- base = dkr_import_current_base_layer(i); +- if (base) { +- const char *base_path; +- +- base_path = strjoina(i->image_root, "/.dkr-", base); +- r = btrfs_subvol_snapshot(base_path, i->temp_path, false, true); +- } else +- r = btrfs_subvol_make(i->temp_path); +- if (r < 0) +- return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path); +- +- j->disk_fd = import_fork_tar(i->temp_path, &i->tar_pid); +- if (j->disk_fd < 0) +- return j->disk_fd; +- +- return 0; +-} +- +-static void dkr_import_job_on_progress(ImportJob *j) { +- DkrImport *i; +- +- assert(j); +- assert(j->userdata); +- +- i = j->userdata; +- +- dkr_import_report_progress( +- i, +- j == i->images_job ? DKR_SEARCHING : +- j == i->tags_job ? DKR_RESOLVING : +- j == i->ancestry_job || j == i->json_job ? DKR_METADATA : +- DKR_DOWNLOADING); +-} +- +-static int dkr_import_pull_layer(DkrImport *i) { +- _cleanup_free_ char *path = NULL; +- const char *url, *layer = NULL; +- int r; +- +- assert(i); +- assert(!i->layer_job); +- assert(!i->temp_path); +- assert(!i->final_path); +- +- for (;;) { +- layer = dkr_import_current_layer(i); +- if (!layer) +- return 0; /* no more layers */ +- +- path = strjoin(i->image_root, "/.dkr-", layer, NULL); +- if (!path) +- return log_oom(); +- +- if (laccess(path, F_OK) < 0) { +- if (errno == ENOENT) +- break; +- +- return log_error_errno(errno, "Failed to check for container: %m"); +- } +- +- log_info("Layer %s already exists, skipping.", layer); +- +- i->current_ancestry++; +- +- free(path); +- path = NULL; +- } +- +- log_info("Pulling layer %s...", layer); +- +- i->final_path = path; +- path = NULL; +- +- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", layer, "/layer"); +- r = import_job_new(&i->layer_job, url, i->glue, i); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate layer job: %m"); +- +- r = dkr_import_add_token(i, i->layer_job); +- if (r < 0) +- return log_oom(); +- +- i->layer_job->on_finished = dkr_import_job_on_finished; +- i->layer_job->on_open_disk = dkr_import_job_on_open_disk; +- i->layer_job->on_progress = dkr_import_job_on_progress; +- +- r = import_job_begin(i->layer_job); +- if (r < 0) +- return log_error_errno(r, "Failed to start layer job: %m"); +- +- return 0; +-} +- +-static void dkr_import_job_on_finished(ImportJob *j) { +- DkrImport *i; +- int r; +- +- assert(j); +- assert(j->userdata); +- +- i = j->userdata; +- if (j->error != 0) { +- if (j == i->images_job) +- log_error_errno(j->error, "Failed to retrieve images list. (Wrong index URL?)"); +- else if (j == i->tags_job) +- log_error_errno(j->error, "Failed to retrieve tags list."); +- else if (j == i->ancestry_job) +- log_error_errno(j->error, "Failed to retrieve ancestry list."); +- else if (j == i->json_job) +- log_error_errno(j->error, "Failed to retrieve json data."); +- else +- log_error_errno(j->error, "Failed to retrieve layer data."); +- +- r = j->error; +- goto finish; +- } +- +- if (i->images_job == j) { +- const char *url; +- +- assert(!i->tags_job); +- assert(!i->ancestry_job); +- assert(!i->json_job); +- assert(!i->layer_job); +- +- if (strv_isempty(i->response_registries)) { +- r = -EBADMSG; +- log_error("Didn't get registry information."); +- goto finish; +- } +- +- log_info("Index lookup succeeded, directed to registry %s.", i->response_registries[0]); +- dkr_import_report_progress(i, DKR_RESOLVING); +- +- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/repositories/", i->name, "/tags/", i->tag); +- r = import_job_new(&i->tags_job, url, i->glue, i); +- if (r < 0) { +- log_error_errno(r, "Failed to allocate tags job: %m"); +- goto finish; +- } +- +- r = dkr_import_add_token(i, i->tags_job); +- if (r < 0) { +- log_oom(); +- goto finish; +- } +- +- i->tags_job->on_finished = dkr_import_job_on_finished; +- i->tags_job->on_progress = dkr_import_job_on_progress; +- +- r = import_job_begin(i->tags_job); +- if (r < 0) { +- log_error_errno(r, "Failed to start tags job: %m"); +- goto finish; +- } +- +- } else if (i->tags_job == j) { +- const char *url; +- char *id = NULL; +- +- assert(!i->ancestry_job); +- assert(!i->json_job); +- assert(!i->layer_job); +- +- r = parse_id(j->payload, j->payload_size, &id); +- if (r < 0) { +- log_error_errno(r, "Failed to parse JSON id."); +- goto finish; +- } +- +- free(i->id); +- i->id = id; +- +- log_info("Tag lookup succeeded, resolved to layer %s.", i->id); +- dkr_import_report_progress(i, DKR_METADATA); +- +- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/ancestry"); +- r = import_job_new(&i->ancestry_job, url, i->glue, i); +- if (r < 0) { +- log_error_errno(r, "Failed to allocate ancestry job: %m"); +- goto finish; +- } +- +- r = dkr_import_add_token(i, i->ancestry_job); +- if (r < 0) { +- log_oom(); +- goto finish; +- } +- +- i->ancestry_job->on_finished = dkr_import_job_on_finished; +- i->ancestry_job->on_progress = dkr_import_job_on_progress; +- +- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/json"); +- r = import_job_new(&i->json_job, url, i->glue, i); +- if (r < 0) { +- log_error_errno(r, "Failed to allocate json job: %m"); +- goto finish; +- } +- +- r = dkr_import_add_token(i, i->json_job); +- if (r < 0) { +- log_oom(); +- goto finish; +- } +- +- i->json_job->on_finished = dkr_import_job_on_finished; +- i->json_job->on_progress = dkr_import_job_on_progress; +- +- r = import_job_begin(i->ancestry_job); +- if (r < 0) { +- log_error_errno(r, "Failed to start ancestry job: %m"); +- goto finish; +- } +- +- r = import_job_begin(i->json_job); +- if (r < 0) { +- log_error_errno(r, "Failed to start json job: %m"); +- goto finish; +- } +- +- } else if (i->ancestry_job == j) { +- char **ancestry = NULL, **k; +- unsigned n; +- +- assert(!i->layer_job); +- +- r = parse_ancestry(j->payload, j->payload_size, &ancestry); +- if (r < 0) { +- log_error_errno(r, "Failed to parse JSON id."); +- goto finish; +- } +- +- n = strv_length(ancestry); +- if (n <= 0 || !streq(ancestry[n-1], i->id)) { +- log_error("Ancestry doesn't end in main layer."); +- strv_free(ancestry); +- r = -EBADMSG; +- goto finish; +- } +- +- log_info("Ancestor lookup succeeded, requires layers:\n"); +- STRV_FOREACH(k, ancestry) +- log_info("\t%s", *k); +- +- strv_free(i->ancestry); +- i->ancestry = ancestry; +- i->n_ancestry = n; +- i->current_ancestry = 0; +- +- dkr_import_report_progress(i, DKR_DOWNLOADING); +- +- r = dkr_import_pull_layer(i); +- if (r < 0) +- goto finish; +- +- } else if (i->layer_job == j) { +- assert(i->temp_path); +- assert(i->final_path); +- +- j->disk_fd = safe_close(j->disk_fd); +- +- if (i->tar_pid > 0) { +- r = wait_for_terminate_and_warn("tar", i->tar_pid, true); +- i->tar_pid = 0; +- if (r < 0) +- goto finish; +- } +- +- r = aufs_resolve(i->temp_path); +- if (r < 0) { +- log_error_errno(r, "Failed to resolve aufs whiteouts: %m"); +- goto finish; +- } +- +- r = btrfs_subvol_set_read_only(i->temp_path, true); +- if (r < 0) { +- log_error_errno(r, "Failed to mark snapshot read-only: %m"); +- goto finish; +- } +- +- if (rename(i->temp_path, i->final_path) < 0) { +- log_error_errno(errno, "Failed to rename snaphsot: %m"); +- goto finish; +- } +- +- log_info("Completed writing to layer %s.", i->final_path); +- +- i->layer_job = import_job_unref(i->layer_job); +- free(i->temp_path); +- i->temp_path = NULL; +- free(i->final_path); +- i->final_path = NULL; +- +- i->current_ancestry ++; +- r = dkr_import_pull_layer(i); +- if (r < 0) +- goto finish; +- +- } else if (i->json_job != j) +- assert_not_reached("Got finished event for unknown curl object"); +- +- if (!dkr_import_is_done(i)) +- return; +- +- dkr_import_report_progress(i, DKR_COPYING); +- +- r = dkr_import_make_local_copy(i); +- if (r < 0) +- goto finish; +- +- r = 0; +- +-finish: +- if (i->on_finished) +- i->on_finished(i, r, i->userdata); +- else +- sd_event_exit(i->event, r); +-} +- +-static int dkr_import_job_on_header(ImportJob *j, const char *header, size_t sz) { +- _cleanup_free_ char *registry = NULL; +- char *token; +- DkrImport *i; +- int r; +- +- assert(j); +- assert(j->userdata); +- +- i = j->userdata; +- +- r = curl_header_strdup(header, sz, HEADER_TOKEN, &token); +- if (r < 0) +- return log_oom(); +- if (r > 0) { +- free(i->response_token); +- i->response_token = token; +- return 0; +- } +- +- r = curl_header_strdup(header, sz, HEADER_REGISTRY, ®istry); +- if (r < 0) +- return log_oom(); +- if (r > 0) { +- char **l, **k; +- +- l = strv_split(registry, ","); +- if (!l) +- return log_oom(); +- +- STRV_FOREACH(k, l) { +- if (!hostname_is_valid(*k)) { +- log_error("Registry hostname is not valid."); +- strv_free(l); +- return -EBADMSG; +- } +- } +- +- strv_free(i->response_registries); +- i->response_registries = l; +- } +- +- return 0; +-} +- +-int dkr_import_pull(DkrImport *i, const char *name, const char *tag, const char *local, bool force_local) { +- const char *url; +- int r; +- +- assert(i); +- +- if (!dkr_name_is_valid(name)) +- return -EINVAL; +- +- if (tag && !dkr_tag_is_valid(tag)) +- return -EINVAL; +- +- if (local && !machine_name_is_valid(local)) +- return -EINVAL; +- +- if (i->images_job) +- return -EBUSY; +- +- if (!tag) +- tag = "latest"; +- +- r = free_and_strdup(&i->local, local); +- if (r < 0) +- return r; +- i->force_local = force_local; +- +- r = free_and_strdup(&i->name, name); +- if (r < 0) +- return r; +- r = free_and_strdup(&i->tag, tag); +- if (r < 0) +- return r; +- +- url = strjoina(i->index_url, "/v1/repositories/", name, "/images"); +- +- r = import_job_new(&i->images_job, url, i->glue, i); +- if (r < 0) +- return r; +- +- r = dkr_import_add_token(i, i->images_job); +- if (r < 0) +- return r; +- +- i->images_job->on_finished = dkr_import_job_on_finished; +- i->images_job->on_header = dkr_import_job_on_header; +- i->images_job->on_progress = dkr_import_job_on_progress; +- +- return import_job_begin(i->images_job); +-} +diff --git a/src/import/import-dkr.h b/src/import/import-dkr.h +deleted file mode 100644 +index 633c767..0000000 +--- a/src/import/import-dkr.h ++++ /dev/null +@@ -1,36 +0,0 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- +-/*** +- This file is part of systemd. +- +- Copyright 2014 Lennart Poettering +- +- 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 . +-***/ +- +-#pragma once +- +-#include "sd-event.h" +-#include "util.h" +- +-typedef struct DkrImport DkrImport; +- +-typedef void (*DkrImportFinished)(DkrImport *import, int error, void *userdata); +- +-int dkr_import_new(DkrImport **import, sd_event *event, const char *index_url, const char *image_root, DkrImportFinished on_finished, void *userdata); +-DkrImport* dkr_import_unref(DkrImport *import); +- +-DEFINE_TRIVIAL_CLEANUP_FUNC(DkrImport*, dkr_import_unref); +- +-int dkr_import_pull(DkrImport *import, const char *name, const char *tag, const char *local, bool force_local); +diff --git a/src/import/importd.c b/src/import/importd.c +index 1222bf3..9aaf991 100644 +--- a/src/import/importd.c ++++ b/src/import/importd.c +@@ -38,7 +38,6 @@ typedef struct Manager Manager; + typedef enum TransferType { + TRANSFER_TAR, + TRANSFER_RAW, +- TRANSFER_DKR, + _TRANSFER_TYPE_MAX, + _TRANSFER_TYPE_INVALID = -1, + } TransferType; +@@ -56,8 +55,6 @@ struct Transfer { + char *local; + bool force_local; + +- char *dkr_index_url; +- + pid_t pid; + + int log_fd; +@@ -91,7 +88,6 @@ struct Manager { + static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = { + [TRANSFER_TAR] = "tar", + [TRANSFER_RAW] = "raw", +- [TRANSFER_DKR] = "dkr", + }; + + DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType); +@@ -108,7 +104,6 @@ static Transfer *transfer_unref(Transfer *t) { + + free(t->remote); + free(t->local); +- free(t->dkr_index_url); + free(t->object_path); + + if (t->pid > 0) { +@@ -355,7 +350,6 @@ static int transfer_start(Transfer *t) { + "--verify", + NULL, /* verify argument */ + NULL, /* maybe --force */ +- NULL, /* maybe --dkr-index-url */ + NULL, /* the actual URL */ + NULL, /* remote */ + NULL, /* local */ +@@ -410,11 +404,6 @@ static int transfer_start(Transfer *t) { + if (t->force_local) + cmd[k++] = "--force"; + +- if (t->dkr_index_url) { +- cmd[k++] = "--dkr-index-url"; +- cmd[k++] = t->dkr_index_url; +- } +- + cmd[k++] = t->remote; + if (t->local) + cmd[k++] = t->local; +@@ -624,7 +613,7 @@ static int manager_new(Manager **ret) { + return 0; + } + +-static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_index_url, const char *remote) { ++static Transfer *manager_find(Manager *m, TransferType type, const char *remote) { + Transfer *t; + Iterator i; + +@@ -635,8 +624,7 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_ind + HASHMAP_FOREACH(t, m->transfers, i) { + + if (t->type == type && +- streq_ptr(t->remote, remote) && +- streq_ptr(t->dkr_index_url, dkr_index_url)) ++ streq_ptr(t->remote, remote)) + return t; + } + +@@ -689,7 +677,7 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda + + type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_TAR : TRANSFER_RAW; + +- if (manager_find(m, type, NULL, remote)) ++ if (manager_find(m, type, remote)) + return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote); + + r = transfer_new(m, &t); +@@ -719,98 +707,6 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda + return sd_bus_reply_method_return(msg, "uo", id, object); + } + +-static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) { +- _cleanup_(transfer_unrefp) Transfer *t = NULL; +- const char *index_url, *remote, *tag, *local, *verify, *object; +- Manager *m = userdata; +- ImportVerify v; +- int force, r; +- uint32_t id; +- +- assert(bus); +- assert(msg); +- assert(m); +- +- r = bus_verify_polkit_async( +- msg, +- CAP_SYS_ADMIN, +- "org.freedesktop.import1.pull", +- false, +- &m->polkit_registry, +- error); +- if (r < 0) +- return r; +- if (r == 0) +- return 1; /* Will call us back */ +- +- r = sd_bus_message_read(msg, "sssssb", &index_url, &remote, &tag, &local, &verify, &force); +- if (r < 0) +- return r; +- +- if (isempty(index_url)) +- index_url = DEFAULT_DKR_INDEX_URL; +- if (!index_url) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Index URL must be specified."); +- if (!http_url_is_valid(index_url)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Index URL %s is invalid", index_url); +- +- if (!dkr_name_is_valid(remote)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Remote name %s is not valid", remote); +- +- if (isempty(tag)) +- tag = "latest"; +- else if (!dkr_tag_is_valid(tag)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Tag %s is not valid", tag); +- +- if (isempty(local)) +- local = NULL; +- else if (!machine_name_is_valid(local)) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); +- +- if (isempty(verify)) +- v = IMPORT_VERIFY_SIGNATURE; +- else +- v = import_verify_from_string(verify); +- if (v < 0) +- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify); +- +- if (v != IMPORT_VERIFY_NO) +- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "DKR does not support verification."); +- +- if (manager_find(m, TRANSFER_DKR, index_url, remote)) +- return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote); +- +- r = transfer_new(m, &t); +- if (r < 0) +- return r; +- +- t->type = TRANSFER_DKR; +- t->verify = v; +- t->force_local = force; +- +- t->dkr_index_url = strdup(index_url); +- if (!t->dkr_index_url) +- return -ENOMEM; +- +- t->remote = strjoin(remote, ":", tag, NULL); +- if (!t->remote) +- return -ENOMEM; +- +- t->local = strdup(local); +- if (!t->local) +- return -ENOMEM; +- +- r = transfer_start(t); +- if (r < 0) +- return r; +- +- object = t->object_path; +- id = t->id; +- t = NULL; +- +- return sd_bus_reply_method_return(msg, "uo", id, object); +-} +- + static int method_list_transfers(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + Manager *m = userdata; +@@ -956,7 +852,6 @@ static const sd_bus_vtable manager_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), +- SD_BUS_METHOD("PullDkr", "sssssb", "uo", method_pull_dkr, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ListTransfers", NULL, "a(usssdo)", method_list_transfers, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CancelTransfer", "u", NULL, method_cancel_transfer, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_SIGNAL("TransferNew", "uo", 0), +diff --git a/src/import/org.freedesktop.import1.conf b/src/import/org.freedesktop.import1.conf +index ae36af4..ed2539a 100644 +--- a/src/import/org.freedesktop.import1.conf ++++ b/src/import/org.freedesktop.import1.conf +@@ -53,10 +53,6 @@ + send_member="PullRaw"/> + + +- +- + +diff --git a/src/import/pull.c b/src/import/pull.c +index ee3ff68..9cb1088 100644 +--- a/src/import/pull.c ++++ b/src/import/pull.c +@@ -28,13 +28,11 @@ + #include "machine-image.h" + #include "import-tar.h" + #include "import-raw.h" +-#include "import-dkr.h" + #include "import-util.h" + + static bool arg_force = false; + static const char *arg_image_root = "/var/lib/machines"; + static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; +-static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL; + + static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + log_notice("Transfer aborted."); +@@ -214,107 +212,6 @@ static int pull_raw(int argc, char *argv[], void *userdata) { + return -r; + } + +-static void on_dkr_finished(DkrImport *import, int error, void *userdata) { +- sd_event *event = userdata; +- assert(import); +- +- if (error == 0) +- log_info("Operation completed successfully."); +- +- sd_event_exit(event, abs(error)); +-} +- +-static int pull_dkr(int argc, char *argv[], void *userdata) { +- _cleanup_(dkr_import_unrefp) DkrImport *import = NULL; +- _cleanup_event_unref_ sd_event *event = NULL; +- const char *name, *tag, *local; +- int r; +- +- if (!arg_dkr_index_url) { +- log_error("Please specify an index URL with --dkr-index-url="); +- return -EINVAL; +- } +- +- if (arg_verify != IMPORT_VERIFY_NO) { +- log_error("Imports from dkr do not support image verification, please pass --verify=no."); +- return -EINVAL; +- } +- +- tag = strchr(argv[1], ':'); +- if (tag) { +- name = strndupa(argv[1], tag - argv[1]); +- tag++; +- } else { +- name = argv[1]; +- tag = "latest"; +- } +- +- if (!dkr_name_is_valid(name)) { +- log_error("Remote name '%s' is not valid.", name); +- return -EINVAL; +- } +- +- if (!dkr_tag_is_valid(tag)) { +- log_error("Tag name '%s' is not valid.", tag); +- return -EINVAL; +- } +- +- if (argc >= 3) +- local = argv[2]; +- else { +- local = strchr(name, '/'); +- if (local) +- local++; +- else +- local = name; +- } +- +- if (isempty(local) || streq(local, "-")) +- local = NULL; +- +- if (local) { +- if (!machine_name_is_valid(local)) { +- log_error("Local image name '%s' is not valid.", local); +- return -EINVAL; +- } +- +- if (!arg_force) { +- r = image_find(local, NULL); +- if (r < 0) +- return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); +- else if (r > 0) { +- log_error_errno(EEXIST, "Image '%s' already exists.", local); +- return -EEXIST; +- } +- } +- +- log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local); +- } else +- log_info("Pulling '%s' with tag '%s'.", name, tag); +- +- r = sd_event_default(&event); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate event loop: %m"); +- +- assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0); +- sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL); +- sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL); +- +- r = dkr_import_new(&import, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event); +- if (r < 0) +- return log_error_errno(r, "Failed to allocate importer: %m"); +- +- r = dkr_import_pull(import, name, tag, local, arg_force); +- if (r < 0) +- return log_error_errno(r, "Failed to pull image: %m"); +- +- r = sd_event_loop(event); +- if (r < 0) +- return log_error_errno(r, "Failed to run event loop: %m"); +- +- log_info("Exiting."); +- return -r; +-} + + static int help(int argc, char *argv[], void *userdata) { + +@@ -326,11 +223,9 @@ static int help(int argc, char *argv[], void *userdata) { + " --verify= Verify downloaded image, one of: 'no',\n" + " 'checksum', 'signature'.\n" + " --image-root= Image root directory\n" +- " --dkr-index-url=URL Specify index URL to use for downloads\n\n" + "Commands:\n" + " tar URL [NAME] Download a TAR image\n" +- " raw URL [NAME] Download a RAW image\n" +- " dkr REMOTE [NAME] Download a DKR image\n", ++ " raw URL [NAME] Download a RAW image\n", + program_invocation_short_name); + + return 0; +@@ -341,7 +236,6 @@ static int parse_argv(int argc, char *argv[]) { + enum { + ARG_VERSION = 0x100, + ARG_FORCE, +- ARG_DKR_INDEX_URL, + ARG_IMAGE_ROOT, + ARG_VERIFY, + }; +@@ -350,7 +244,6 @@ static int parse_argv(int argc, char *argv[]) { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "force", no_argument, NULL, ARG_FORCE }, +- { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL }, + { "image-root", required_argument, NULL, ARG_IMAGE_ROOT }, + { "verify", required_argument, NULL, ARG_VERIFY }, + {} +@@ -377,15 +270,6 @@ static int parse_argv(int argc, char *argv[]) { + arg_force = true; + break; + +- case ARG_DKR_INDEX_URL: +- if (!http_url_is_valid(optarg)) { +- log_error("Index URL is not valid: %s", optarg); +- return -EINVAL; +- } +- +- arg_dkr_index_url = optarg; +- break; +- + case ARG_IMAGE_ROOT: + arg_image_root = optarg; + break; +@@ -415,7 +299,6 @@ static int import_main(int argc, char *argv[]) { + { "help", VERB_ANY, VERB_ANY, 0, help }, + { "tar", 2, 3, 0, pull_tar }, + { "raw", 2, 3, 0, pull_raw }, +- { "dkr", 2, 3, 0, pull_dkr }, + {} + }; + +diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c +index ef1214a..cfd3162 100644 +--- a/src/machine/machinectl.c ++++ b/src/machine/machinectl.c +@@ -77,7 +77,6 @@ static unsigned arg_lines = 10; + static OutputMode arg_output = OUTPUT_SHORT; + static bool arg_force = false; + static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; +-static const char* arg_dkr_index_url = NULL; + + static void pager_open_if_enabled(void) { + +@@ -1998,78 +1997,6 @@ static int pull_raw(int argc, char *argv[], void *userdata) { + return pull_image_common(bus, m); + } + +-static int pull_dkr(int argc, char *argv[], void *userdata) { +- _cleanup_bus_message_unref_ sd_bus_message *m = NULL; +- const char *local, *remote, *tag; +- sd_bus *bus = userdata; +- int r; +- +- if (arg_verify != IMPORT_VERIFY_NO) { +- log_error("Imports from DKR do not support image verification, please pass --verify=no."); +- return -EINVAL; +- } +- +- remote = argv[1]; +- tag = strchr(remote, ':'); +- if (tag) { +- remote = strndupa(remote, tag - remote); +- tag++; +- } +- +- if (!dkr_name_is_valid(remote)) { +- log_error("DKR name '%s' is invalid.", remote); +- return -EINVAL; +- } +- if (tag && !dkr_tag_is_valid(tag)) { +- log_error("DKR tag '%s' is invalid.", remote); +- return -EINVAL; +- } +- +- if (argc >= 3) +- local = argv[2]; +- else { +- local = strchr(remote, '/'); +- if (local) +- local++; +- else +- local = remote; +- } +- +- if (isempty(local) || streq(local, "-")) +- local = NULL; +- +- if (local) { +- if (!machine_name_is_valid(local)) { +- log_error("Local name %s is not a suitable machine name.", local); +- return -EINVAL; +- } +- } +- +- r = sd_bus_message_new_method_call( +- bus, +- &m, +- "org.freedesktop.import1", +- "/org/freedesktop/import1", +- "org.freedesktop.import1.Manager", +- "PullDkr"); +- if (r < 0) +- return bus_log_create_error(r); +- +- r = sd_bus_message_append( +- m, +- "sssssb", +- arg_dkr_index_url, +- remote, +- tag, +- local, +- import_verify_to_string(arg_verify), +- arg_force); +- if (r < 0) +- return bus_log_create_error(r); +- +- return pull_image_common(bus, m); +-} +- + typedef struct TransferInfo { + uint32_t id; + const char *type; +@@ -2237,8 +2164,6 @@ static int help(int argc, char *argv[], void *userdata) { + " --verify=MODE Verification mode for downloaded images (no,\n" + " checksum, signature)\n" + " --force Download image even if already exists\n" +- " --dkr-index-url=URL Specify the index URL to use for DKR image\n" +- " downloads\n\n" + "Machine Commands:\n" + " list List running VMs and containers\n" + " status NAME... Show VM/container details\n" +@@ -2265,7 +2190,6 @@ static int help(int argc, char *argv[], void *userdata) { + "Image Transfer Commands:\n" + " pull-tar URL [NAME] Download a TAR container image\n" + " pull-raw URL [NAME] Download a RAW container or VM image\n" +- " pull-dkr REMOTE [NAME] Download a DKR container image\n" + " list-transfers Show list of downloads in progress\n" + " cancel-transfer Cancel a download\n" + , program_invocation_short_name); +@@ -2284,8 +2208,7 @@ static int parse_argv(int argc, char *argv[]) { + ARG_MKDIR, + ARG_NO_ASK_PASSWORD, + ARG_VERIFY, +- ARG_FORCE, +- ARG_DKR_INDEX_URL, ++ ARG_FORCE + }; + + static const struct option options[] = { +@@ -2308,7 +2231,6 @@ static int parse_argv(int argc, char *argv[]) { + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + { "verify", required_argument, NULL, ARG_VERIFY }, + { "force", no_argument, NULL, ARG_FORCE }, +- { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL }, + {} + }; + +@@ -2421,15 +2343,6 @@ static int parse_argv(int argc, char *argv[]) { + arg_force = true; + break; + +- case ARG_DKR_INDEX_URL: +- if (!http_url_is_valid(optarg)) { +- log_error("Index URL is invalid: %s", optarg); +- return -EINVAL; +- } +- +- arg_dkr_index_url = optarg; +- break; +- + case '?': + return -EINVAL; + +@@ -2467,7 +2380,6 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { + { "disable", 2, VERB_ANY, 0, enable_machine }, + { "pull-tar", 2, 3, 0, pull_tar }, + { "pull-raw", 2, 3, 0, pull_raw }, +- { "pull-dkr", 2, 3, 0, pull_dkr }, + { "list-transfers", VERB_ANY, 1, 0, list_transfers }, + { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer }, + {} +diff --git a/src/shared/import-util.c b/src/shared/import-util.c +index 660d92a..c0aba30 100644 +--- a/src/shared/import-util.c ++++ b/src/shared/import-util.c +@@ -149,34 +149,3 @@ int raw_strip_suffixes(const char *p, char **ret) { + + return 0; + } +- +-bool dkr_name_is_valid(const char *name) { +- const char *slash, *p; +- +- if (isempty(name)) +- return false; +- +- slash = strchr(name, '/'); +- if (!slash) +- return false; +- +- if (!filename_is_valid(slash + 1)) +- return false; +- +- p = strndupa(name, slash - name); +- if (!filename_is_valid(p)) +- return false; +- +- return true; +-} +- +-bool dkr_id_is_valid(const char *id) { +- +- if (!filename_is_valid(id)) +- return false; +- +- if (!in_charset(id, "0123456789abcdef")) +- return false; +- +- return true; +-} +diff --git a/src/shared/import-util.h b/src/shared/import-util.h +index ff155b0..22773c5 100644 +--- a/src/shared/import-util.h ++++ b/src/shared/import-util.h +@@ -41,7 +41,3 @@ ImportVerify import_verify_from_string(const char *s) _pure_; + + int tar_strip_suffixes(const char *name, char **ret); + int raw_strip_suffixes(const char *name, char **ret); +- +-bool dkr_name_is_valid(const char *name); +-bool dkr_id_is_valid(const char *id); +-#define dkr_tag_is_valid(tag) filename_is_valid(tag) diff --git a/SOURCES/0325-import-add-support-for-gpg2-for-verifying-imported-i.patch b/SOURCES/0325-import-add-support-for-gpg2-for-verifying-imported-i.patch new file mode 100644 index 0000000..0b5c5bc --- /dev/null +++ b/SOURCES/0325-import-add-support-for-gpg2-for-verifying-imported-i.patch @@ -0,0 +1,88 @@ +From 1b7d1234cd22bb0fd2677d54dc670a6d2c6f8089 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Mar 2015 20:24:11 +0100 +Subject: [PATCH] import: add support for gpg2 for verifying imported images + +gpg2 insists on created a trust db even if we tun off all trust db +support. Hence create a temporary home where the trust db is placed, and +remove it after use. + +Cherry-picked from: 0acfdffe9417b4218e97b6d981c99a1a85e633c9 +Resolves: #1284974 +--- + src/import/import-common.c | 21 ++++++++++++++++++--- + 1 file changed, 18 insertions(+), 3 deletions(-) + +diff --git a/src/import/import-common.c b/src/import/import-common.c +index 2acf380..f10a453 100644 +--- a/src/import/import-common.c ++++ b/src/import/import-common.c +@@ -281,8 +281,9 @@ int import_verify( + _cleanup_free_ char *fn = NULL; + _cleanup_close_ int sig_file = -1; + const char *p, *line; +- char sig_file_path[] = "/tmp/sigXXXXXX"; ++ char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX"; + _cleanup_sigkill_wait_ pid_t pid = 0; ++ bool gpg_home_created = false; + int r; + + assert(main_job); +@@ -347,6 +348,13 @@ int import_verify( + goto finish; + } + ++ if (!mkdtemp(gpg_home)) { ++ r = log_error_errno(errno, "Failed to create tempory home for gpg: %m"); ++ goto finish; ++ } ++ ++ gpg_home_created = true; ++ + pid = fork(); + if (pid < 0) + return log_error_errno(errno, "Failed to fork off gpg: %m"); +@@ -359,13 +367,14 @@ int import_verify( + "--no-auto-check-trustdb", + "--batch", + "--trust-model=always", +- NULL, /* keyring to use */ ++ NULL, /* --homedir= */ ++ NULL, /* --keyring= */ + NULL, /* --verify */ + NULL, /* signature file */ + NULL, /* dash */ + NULL /* trailing NULL */ + }; +- unsigned k = ELEMENTSOF(cmd) - 5; ++ unsigned k = ELEMENTSOF(cmd) - 6; + int null_fd; + + /* Child */ +@@ -398,6 +407,8 @@ int import_verify( + if (null_fd != STDOUT_FILENO) + null_fd = safe_close(null_fd); + ++ cmd[k++] = strjoina("--homedir=", gpg_home); ++ + /* We add the user keyring only to the command line + * arguments, if it's around since gpg fails + * otherwise. */ +@@ -415,6 +426,7 @@ int import_verify( + fd_cloexec(STDOUT_FILENO, false); + fd_cloexec(STDERR_FILENO, false); + ++ execvp("gpg2", (char * const *) cmd); + execvp("gpg", (char * const *) cmd); + log_error_errno(errno, "Failed to execute gpg: %m"); + _exit(EXIT_FAILURE); +@@ -446,6 +458,9 @@ finish: + if (sig_file >= 0) + unlink(sig_file_path); + ++ if (gpg_home_created) ++ rm_rf_dangerous(gpg_home, false, true, false); ++ + return r; + } + diff --git a/SOURCES/0326-nspawn-when-connected-to-pipes-for-stdin-stdout-pass.patch b/SOURCES/0326-nspawn-when-connected-to-pipes-for-stdin-stdout-pass.patch new file mode 100644 index 0000000..5145384 --- /dev/null +++ b/SOURCES/0326-nspawn-when-connected-to-pipes-for-stdin-stdout-pass.patch @@ -0,0 +1,293 @@ +From 98e5c02b1602eaaac5c63045fa7a06e40249445e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 18 Feb 2015 23:32:55 +0100 +Subject: [PATCH] nspawn: when connected to pipes for stdin/stdout, pass them + as-is to PID 1 + +Previously we always invoked the container PID 1 on /dev/console of the +container. With this change we do so only if nspawn was invoked +interactively (i.e. its stdin/stdout was connected to a TTY). In all other +cases we directly pass through the fds unmodified. + +This has the benefit that nspawn can be added into shell pipelines. + +https://bugs.freedesktop.org/show_bug.cgi?id=87732 + +Cherry-picked from: 9c857b9d160c10b4454fc9f83442c1878343422f +Resolves: #1307080 +--- + src/machine/machinectl.c | 2 +- + src/nspawn/nspawn.c | 48 +++++++++++++++++-------------- + src/run/run.c | 2 +- + src/shared/ptyfwd.c | 75 ++++++++++++++++++++++++++++-------------------- + src/shared/ptyfwd.h | 2 +- + 5 files changed, 74 insertions(+), 55 deletions(-) + +diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c +index cfd3162..1a58aea 100644 +--- a/src/machine/machinectl.c ++++ b/src/machine/machinectl.c +@@ -1427,7 +1427,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { + sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); + sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); + +- r = pty_forward_new(event, master, true, &forward); ++ r = pty_forward_new(event, master, true, false, &forward); + if (r < 0) + return log_error_errno(r, "Failed to create PTY forwarder: %m"); + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index 78bd584..a37b640 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -3581,6 +3581,7 @@ int main(int argc, char *argv[]) { + int ret = EXIT_SUCCESS; + union in_addr_union exposed = {}; + _cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT; ++ bool interactive; + + log_parse_environment(); + log_open(); +@@ -3754,6 +3755,8 @@ int main(int argc, char *argv[]) { + goto finish; + } + ++ interactive = isatty(STDIN_FILENO) > 0 && isatty(STDOUT_FILENO) > 0; ++ + master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY); + if (master < 0) { + r = log_error_errno(errno, "Failed to acquire pseudo tty: %m"); +@@ -3766,15 +3769,15 @@ int main(int argc, char *argv[]) { + goto finish; + } + +- if (!arg_quiet) +- log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.", +- arg_machine, arg_image ?: arg_directory); +- + if (unlockpt(master) < 0) { + r = log_error_errno(errno, "Failed to unlock tty: %m"); + goto finish; + } + ++ if (!arg_quiet) ++ log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.", ++ arg_machine, arg_image ?: arg_directory); ++ + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1); + assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); +@@ -3860,9 +3863,6 @@ int main(int argc, char *argv[]) { + + master = safe_close(master); + +- close_nointr(STDIN_FILENO); +- close_nointr(STDOUT_FILENO); +- close_nointr(STDERR_FILENO); + + kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]); + rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); +@@ -3870,21 +3870,27 @@ int main(int argc, char *argv[]) { + reset_all_signal_handlers(); + reset_signal_mask(); + +- r = open_terminal(console, O_RDWR); +- if (r != STDIN_FILENO) { +- if (r >= 0) { +- safe_close(r); +- r = -EINVAL; +- } ++ if (interactive) { ++ close_nointr(STDIN_FILENO); ++ close_nointr(STDOUT_FILENO); ++ close_nointr(STDERR_FILENO); + +- log_error_errno(r, "Failed to open console: %m"); +- _exit(EXIT_FAILURE); +- } ++ r = open_terminal(console, O_RDWR); ++ if (r != STDIN_FILENO) { ++ if (r >= 0) { ++ safe_close(r); ++ r = -EINVAL; ++ } + +- if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO || +- dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) { +- log_error_errno(errno, "Failed to duplicate console: %m"); +- _exit(EXIT_FAILURE); ++ log_error_errno(r, "Failed to open console: %m"); ++ _exit(EXIT_FAILURE); ++ } ++ ++ if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO || ++ dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) { ++ log_error_errno(errno, "Failed to duplicate console: %m"); ++ _exit(EXIT_FAILURE); ++ } + } + + if (setsid() < 0) { +@@ -4227,7 +4233,7 @@ int main(int argc, char *argv[]) { + + rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); + +- r = pty_forward_new(event, master, true, &forward); ++ r = pty_forward_new(event, master, true, !interactive, &forward); + if (r < 0) { + log_error_errno(r, "Failed to create PTY forwarder: %m"); + goto finish; +diff --git a/src/run/run.c b/src/run/run.c +index dd1338f..4680342 100644 +--- a/src/run/run.c ++++ b/src/run/run.c +@@ -780,7 +780,7 @@ static int start_transient_service( + if (!arg_quiet) + log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service); + +- r = pty_forward_new(event, master, false, &forward); ++ r = pty_forward_new(event, master, false, false, &forward); + if (r < 0) + return log_error_errno(r, "Failed to create PTY forwarder: %m"); + +diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c +index 88b3f4e..4402af1 100644 +--- a/src/shared/ptyfwd.c ++++ b/src/shared/ptyfwd.c +@@ -42,6 +42,8 @@ struct PTYForward { + struct termios saved_stdin_attr; + struct termios saved_stdout_attr; + ++ bool read_only:1; ++ + bool saved_stdin:1; + bool saved_stdout:1; + +@@ -298,7 +300,13 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo * + return 0; + } + +-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward **ret) { ++int pty_forward_new( ++ sd_event *event, ++ int master, ++ bool ignore_vhangup, ++ bool read_only, ++ PTYForward **ret) { ++ + _cleanup_(pty_forward_freep) PTYForward *f = NULL; + struct winsize ws; + int r; +@@ -307,6 +315,7 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward + if (!f) + return -ENOMEM; + ++ f->read_only = read_only; + f->ignore_vhangup = ignore_vhangup; + + if (event) +@@ -317,13 +326,15 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward + return r; + } + +- r = fd_nonblock(STDIN_FILENO, true); +- if (r < 0) +- return r; ++ if (!read_only) { ++ r = fd_nonblock(STDIN_FILENO, true); ++ if (r < 0) ++ return r; + +- r = fd_nonblock(STDOUT_FILENO, true); +- if (r < 0) +- return r; ++ r = fd_nonblock(STDOUT_FILENO, true); ++ if (r < 0) ++ return r; ++ } + + r = fd_nonblock(master, true); + if (r < 0) +@@ -334,36 +345,34 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0) + (void)ioctl(master, TIOCSWINSZ, &ws); + +- if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) { +- struct termios raw_stdin_attr; +- +- f->saved_stdin = true; ++ if (!read_only) { ++ if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) { ++ struct termios raw_stdin_attr; + +- raw_stdin_attr = f->saved_stdin_attr; +- cfmakeraw(&raw_stdin_attr); +- raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag; +- tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr); +- } ++ f->saved_stdin = true; + +- if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) { +- struct termios raw_stdout_attr; ++ raw_stdin_attr = f->saved_stdin_attr; ++ cfmakeraw(&raw_stdin_attr); ++ raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag; ++ tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr); ++ } + +- f->saved_stdout = true; ++ if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) { ++ struct termios raw_stdout_attr; + +- raw_stdout_attr = f->saved_stdout_attr; +- cfmakeraw(&raw_stdout_attr); +- raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag; +- raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag; +- tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr); +- } ++ f->saved_stdout = true; + +- r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f); +- if (r < 0) +- return r; ++ raw_stdout_attr = f->saved_stdout_attr; ++ cfmakeraw(&raw_stdout_attr); ++ raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag; ++ raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag; ++ tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr); ++ } + +- r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f); +- if (r < 0 && r != -EPERM) +- return r; ++ r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f); ++ if (r < 0 && r != -EPERM) ++ return r; ++ } + + r = sd_event_add_io(f->event, &f->stdout_event_source, STDOUT_FILENO, EPOLLOUT|EPOLLET, on_stdout_event, f); + if (r == -EPERM) +@@ -372,6 +381,10 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward + else if (r < 0) + return r; + ++ r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f); ++ if (r < 0) ++ return r; ++ + r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f); + if (r < 0) + return r; +diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h +index d3e229b..6208a54 100644 +--- a/src/shared/ptyfwd.h ++++ b/src/shared/ptyfwd.h +@@ -30,7 +30,7 @@ + + typedef struct PTYForward PTYForward; + +-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward **f); ++int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, bool read_only, PTYForward **f); + PTYForward *pty_forward_free(PTYForward *f); + + int pty_forward_get_last_char(PTYForward *f, char *ch); diff --git a/SOURCES/0327-mount-remove-obsolete-n.patch b/SOURCES/0327-mount-remove-obsolete-n.patch new file mode 100644 index 0000000..c919efc --- /dev/null +++ b/SOURCES/0327-mount-remove-obsolete-n.patch @@ -0,0 +1,55 @@ +From 9592604df60795ad8b58aa11311a26f267385bae Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Tue, 28 Jul 2015 11:31:45 +0200 +Subject: [PATCH] mount: remove obsolete -n + +It seems that systemd still uses legacy -n option. The option has been +originally designed to avoid write to /etc/mtab during boot when root +FS is not ready or read-only. + +This is not necessary for long time, because /etc/mtab is not a real +file (it's symlink) and write to the file is impossible. All utils +should be able to detect the symlink and ignore mtab. This concept is +supported for very long time before systemd. + +The userspase mount options are currently maintained by libmount +(mount(8) and mount.nfs) in /run/mount) which is tmpfs initialized +during early boot. + +(cherry picked from commit 6f20f850f79df365c2533195214127142013d317) +Resolves: #1339721 +--- + src/core/mount.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 23f63ce..fe967bc 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -881,8 +881,6 @@ static void mount_enter_unmounting(Mount *m) { + m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT; + + r = exec_command_set(m->control_command, "/bin/umount", m->where, NULL); +- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) +- r = exec_command_append(m->control_command, "-n", NULL); + if (r < 0) + goto fail; + +@@ -935,8 +933,6 @@ static void mount_enter_mounting(Mount *m) { + + r = exec_command_set(m->control_command, "/bin/mount", + m->parameters_fragment.what, m->where, NULL); +- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) +- r = exec_command_append(m->control_command, "-n", NULL); + if (r >= 0 && m->sloppy_options) + r = exec_command_append(m->control_command, "-s", NULL); + if (r >= 0 && m->parameters_fragment.fstype) +@@ -985,8 +981,6 @@ static void mount_enter_remounting(Mount *m) { + r = exec_command_set(m->control_command, "/bin/mount", + m->parameters_fragment.what, m->where, + "-o", o, NULL); +- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) +- r = exec_command_append(m->control_command, "-n", NULL); + if (r >= 0 && m->sloppy_options) + r = exec_command_append(m->control_command, "-s", NULL); + if (r >= 0 && m->parameters_fragment.fstype) diff --git a/SOURCES/0328-core-don-t-log-job-status-message-in-case-job-was-ef.patch b/SOURCES/0328-core-don-t-log-job-status-message-in-case-job-was-ef.patch new file mode 100644 index 0000000..7047551 --- /dev/null +++ b/SOURCES/0328-core-don-t-log-job-status-message-in-case-job-was-ef.patch @@ -0,0 +1,244 @@ +From a7ec486dede56ab2ec28132133becf11e5685884 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 16 May 2016 17:24:51 +0200 +Subject: [PATCH] core: don't log job status message in case job was + effectively NOP (#3199) + +We currently generate log message about unit being started even when +unit was started already and job didn't do anything. This is because job +was requested explicitly and hence became anchor job of the transaction +thus we could not eliminate it. That is fine but, let's not pollute +journal with useless log messages. + +$ systemctl start systemd-resolved +$ systemctl start systemd-resolved +$ systemctl start systemd-resolved + +Current state: +$ journalctl -u systemd-resolved | grep Started + +May 05 15:31:42 rawhide systemd[1]: Started Network Name Resolution. +May 05 15:31:59 rawhide systemd[1]: Started Network Name Resolution. +May 05 15:32:01 rawhide systemd[1]: Started Network Name Resolution. + +After patch applied: +$ journalctl -u systemd-resolved | grep Started + +May 05 16:42:12 rawhide systemd[1]: Started Network Name Resolution. + +Fixes #1723 + +Cherry-picked from: 833f92ad39beca0e954e91e5764ffc83f8d0c1cf +Resolves: #1280014 +--- + src/core/dbus-job.c | 2 +- + src/core/job.c | 33 ++++++++++++++++++--------------- + src/core/job.h | 2 +- + src/core/manager.c | 2 +- + src/core/transaction.c | 2 +- + src/core/unit.c | 12 ++++++------ + 6 files changed, 28 insertions(+), 25 deletions(-) + +diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c +index 8b5ea25..7ce5d57 100644 +--- a/src/core/dbus-job.c ++++ b/src/core/dbus-job.c +@@ -84,7 +84,7 @@ int bus_job_method_cancel(sd_bus *bus, sd_bus_message *message, void *userdata, + if (r < 0) + return r; + +- job_finish_and_invalidate(j, JOB_CANCELED, true); ++ job_finish_and_invalidate(j, JOB_CANCELED, true, false); + + return sd_bus_reply_method_return(message, NULL); + } +diff --git a/src/core/job.c b/src/core/job.c +index 7416386..c2876de 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -190,7 +190,7 @@ Job* job_install(Job *j) { + + if (uj) { + if (job_type_is_conflicting(uj->type, j->type)) +- job_finish_and_invalidate(uj, JOB_CANCELED, false); ++ job_finish_and_invalidate(uj, JOB_CANCELED, false, false); + else { + /* not conflicting, i.e. mergeable */ + +@@ -571,19 +571,19 @@ int job_run_and_invalidate(Job *j) { + j = manager_get_job(m, id); + if (j) { + if (r == -EALREADY) +- r = job_finish_and_invalidate(j, JOB_DONE, true); ++ r = job_finish_and_invalidate(j, JOB_DONE, true, true); + else if (r == -EBADR) +- r = job_finish_and_invalidate(j, JOB_SKIPPED, true); ++ r = job_finish_and_invalidate(j, JOB_SKIPPED, true, false); + else if (r == -ENOEXEC) +- r = job_finish_and_invalidate(j, JOB_INVALID, true); ++ r = job_finish_and_invalidate(j, JOB_INVALID, true, false); + else if (r == -EPROTO) +- r = job_finish_and_invalidate(j, JOB_ASSERT, true); ++ r = job_finish_and_invalidate(j, JOB_ASSERT, true, false); + else if (r == -ENOTSUP) +- r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true); ++ r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false); + else if (r == -EAGAIN) + job_set_state(j, JOB_WAITING); + else if (r < 0) +- r = job_finish_and_invalidate(j, JOB_FAILED, true); ++ r = job_finish_and_invalidate(j, JOB_FAILED, true, false); + } + + return r; +@@ -792,7 +792,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) { + NULL); + } + +-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { ++int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) { + Unit *u; + Unit *other; + JobType t; +@@ -810,8 +810,11 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { + log_unit_debug(u->id, "Job %s/%s finished, result=%s", + u->id, job_type_to_string(t), job_result_to_string(result)); + +- job_print_status_message(u, t, result); +- job_log_status_message(u, t, result); ++ /* If this job did nothing to respective unit we don't log the status message */ ++ if (!already) { ++ job_print_status_message(u, t, result); ++ job_log_status_message(u, t, result); ++ } + + job_add_to_dbus_queue(j); + +@@ -842,20 +845,20 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) +- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); ++ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true, false); + + SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) +- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); ++ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true, false); + + SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) + if (other->job && + !other->job->override && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) +- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); ++ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true, false); + + } else if (t == JOB_STOP) { + +@@ -863,7 +866,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { + if (other->job && + (other->job->type == JOB_START || + other->job->type == JOB_VERIFY_ACTIVE)) +- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true); ++ job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true, false); + } + } + +@@ -911,7 +914,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user + log_unit_warning(j->unit->id, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type)); + + u = j->unit; +- job_finish_and_invalidate(j, JOB_TIMEOUT, true); ++ job_finish_and_invalidate(j, JOB_TIMEOUT, true, false); + + failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg); + +diff --git a/src/core/job.h b/src/core/job.h +index d967b68..e4191ee 100644 +--- a/src/core/job.h ++++ b/src/core/job.h +@@ -220,7 +220,7 @@ void job_add_to_dbus_queue(Job *j); + int job_start_timer(Job *j); + + int job_run_and_invalidate(Job *j); +-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive); ++int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already); + + char *job_dbus_path(Job *j); + +diff --git a/src/core/manager.c b/src/core/manager.c +index a1504bf..ee456fb 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1426,7 +1426,7 @@ void manager_clear_jobs(Manager *m) { + + while ((j = hashmap_first(m->jobs))) + /* No need to recurse. We're cancelling all jobs. */ +- job_finish_and_invalidate(j, JOB_CANCELED, false); ++ job_finish_and_invalidate(j, JOB_CANCELED, false, false); + } + + static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) { +diff --git a/src/core/transaction.c b/src/core/transaction.c +index b0b3d6b..aed64fa 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -592,7 +592,7 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { + /* Not invalidating recursively. Avoids triggering + * OnFailure= actions of dependent jobs. Also avoids + * invalidating our iterator. */ +- job_finish_and_invalidate(j, JOB_CANCELED, false); ++ job_finish_and_invalidate(j, JOB_CANCELED, false, false); + } + } + +diff --git a/src/core/unit.c b/src/core/unit.c +index db5aa98..d6ead7d 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -1851,12 +1851,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su + case JOB_VERIFY_ACTIVE: + + if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) +- job_finish_and_invalidate(u->job, JOB_DONE, true); ++ job_finish_and_invalidate(u->job, JOB_DONE, true, false); + else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) { + unexpected = true; + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) +- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); ++ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false); + } + + break; +@@ -1866,12 +1866,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su + + if (u->job->state == JOB_RUNNING) { + if (ns == UNIT_ACTIVE) +- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true); ++ job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true, false); + else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) { + unexpected = true; + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) +- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true); ++ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false); + } + } + +@@ -1882,10 +1882,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su + case JOB_TRY_RESTART: + + if (UNIT_IS_INACTIVE_OR_FAILED(ns)) +- job_finish_and_invalidate(u->job, JOB_DONE, true); ++ job_finish_and_invalidate(u->job, JOB_DONE, true, false); + else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) { + unexpected = true; +- job_finish_and_invalidate(u->job, JOB_FAILED, true); ++ job_finish_and_invalidate(u->job, JOB_FAILED, true, false); + } + + break; diff --git a/SOURCES/0329-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch b/SOURCES/0329-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch new file mode 100644 index 0000000..fd0463f --- /dev/null +++ b/SOURCES/0329-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch @@ -0,0 +1,489 @@ +From 92b12c7dc013c95bd0d35bae99ff6df023ce0e1f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 4 May 2016 20:43:23 +0200 +Subject: [PATCH] core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent + notification + +dbus-daemon currently uses a backlog of 30 on its D-bus system bus socket. On +overloaded systems this means that only 30 connections may be queued without +dbus-daemon processing them before further connection attempts fail. Our +cgroups-agent binary so far used D-Bus for its messaging, and hitting this +limit hence may result in us losing cgroup empty messages. + +This patch adds a seperate cgroup agent socket of type AF_UNIX/SOCK_DGRAM. +Since sockets of these types need no connection set up, no listen() backlog +applies. Our cgroup-agent binary will hence simply block as long as it can't +enqueue its datagram message, so that we won't lose cgroup empty messages as +likely anymore. + +This also rearranges the ordering of the processing of SIGCHLD signals, service +notification messages (sd_notify()...) and the two types of cgroup +notifications (inotify for the unified hierarchy support, and agent for the +classic hierarchy support). We now always process events for these in the +following order: + + 1. service notification messages (SD_EVENT_PRIORITY_NORMAL-7) + 2. SIGCHLD signals (SD_EVENT_PRIORITY_NORMAL-6) + 3. cgroup inotify and cgroup agent (SD_EVENT_PRIORITY_NORMAL-5) + +This is because when receiving SIGCHLD we invalidate PID information, which we +need to process the service notification messages which are bound to PIDs. +Hence the order between the first two items. And we want to process SIGCHLD +metadata to detect whether a service is gone, before using cgroup +notifications, to decide when a service is gone, since the former carries more +useful metadata. + +Related to this: +https://bugs.freedesktop.org/show_bug.cgi?id=95264 +https://github.com/systemd/systemd/issues/1961 + +Cherry-picked from: d8fdc62037b5b0a9fd603ad5efd6b49f956f86b5 +Resolves: #1305608 +--- + src/cgroups-agent/cgroups-agent.c | 48 ++++++------ + src/core/cgroup.c | 2 + + src/core/dbus.c | 56 +++++++------- + src/core/dbus.h | 2 + + src/core/manager.c | 149 ++++++++++++++++++++++++++++++++++++-- + src/core/manager.h | 3 + + 6 files changed, 198 insertions(+), 62 deletions(-) + +diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c +index 529e843..2fe6583 100644 +--- a/src/cgroups-agent/cgroups-agent.c ++++ b/src/cgroups-agent/cgroups-agent.c +@@ -1,5 +1,3 @@ +-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +- + /*** + This file is part of systemd. + +@@ -20,14 +18,21 @@ + ***/ + + #include ++#include + +-#include "sd-bus.h" + #include "log.h" +-#include "bus-util.h" ++#include "socket-util.h" + + int main(int argc, char *argv[]) { +- _cleanup_bus_close_unref_ sd_bus *bus = NULL; +- int r; ++ ++ static const union sockaddr_union sa = { ++ .un.sun_family = AF_UNIX, ++ .un.sun_path = "/run/systemd/cgroups-agent", ++ }; ++ ++ _cleanup_close_ int fd = -1; ++ ssize_t n; ++ size_t l; + + if (argc != 2) { + log_error("Incorrect number of arguments."); +@@ -38,27 +43,22 @@ int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + +- /* We send this event to the private D-Bus socket and then the +- * system instance will forward this to the system bus. We do +- * this to avoid an activation loop when we start dbus when we +- * are called when the dbus service is shut down. */ +- +- r = bus_open_system_systemd(&bus); +- if (r < 0) { +- /* If we couldn't connect we assume this was triggered +- * while systemd got restarted/transitioned from +- * initrd to the system, so let's ignore this */ +- log_debug_errno(r, "Failed to get D-Bus connection: %m"); ++ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); ++ if (fd < 0) { ++ log_debug_errno(errno, "Failed to allocate socket: %m"); ++ return EXIT_FAILURE; ++ } ++ ++ l = strlen(argv[1]); ++ ++ n = sendto(fd, argv[1], l, 0, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); ++ if (n < 0) { ++ log_debug_errno(errno, "Failed to send cgroups agent message: %m"); + return EXIT_FAILURE; + } + +- r = sd_bus_emit_signal(bus, +- "/org/freedesktop/systemd1/agent", +- "org.freedesktop.systemd1.Agent", +- "Released", +- "s", argv[1]); +- if (r < 0) { +- log_debug_errno(r, "Failed to send signal message on private connection: %m"); ++ if ((size_t) n != l) { ++ log_debug("Datagram size mismatch"); + return EXIT_FAILURE; + } + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 10fdcc9..b7f08fb 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -1028,6 +1028,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) { + assert(m); + assert(cgroup); + ++ log_debug("Got cgroup empty notification for: %s", cgroup); ++ + u = manager_get_unit_by_cgroup(m, cgroup); + if (u) { + r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true); +diff --git a/src/core/dbus.c b/src/core/dbus.c +index 85b5174..29524d4 100644 +--- a/src/core/dbus.c ++++ b/src/core/dbus.c +@@ -72,12 +72,37 @@ int bus_send_queued_message(Manager *m) { + return 0; + } + ++int bus_forward_agent_released(Manager *m, const char *path) { ++ int r; ++ ++ assert(m); ++ assert(path); ++ ++ if (!m->running_as == SYSTEMD_SYSTEM) ++ return 0; ++ ++ if (!m->system_bus) ++ return 0; ++ ++ /* If we are running a system instance we forward the agent message on the system bus, so that the user ++ * instances get notified about this, too */ ++ ++ r = sd_bus_emit_signal(m->system_bus, ++ "/org/freedesktop/systemd1/agent", ++ "org.freedesktop.systemd1.Agent", ++ "Released", ++ "s", path); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to propagate agent release message: %m"); ++ ++ return 1; ++} ++ + static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + const char *cgroup; + int r; + +- assert(bus); + assert(message); + assert(m); + +@@ -88,16 +113,6 @@ static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *use + } + + manager_notify_cgroup_empty(m, cgroup); +- +- if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) { +- /* If we are running as system manager, forward the +- * message to the system bus */ +- +- r = sd_bus_send(m->system_bus, message, NULL); +- if (r < 0) +- log_warning_errno(r, "Failed to forward Released message: %m"); +- } +- + return 0; + } + +@@ -679,25 +694,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void + return 0; + } + +- if (m->running_as == SYSTEMD_SYSTEM) { +- /* When we run as system instance we get the Released +- * signal via a direct connection */ +- +- r = sd_bus_add_match( +- bus, +- NULL, +- "type='signal'," +- "interface='org.freedesktop.systemd1.Agent'," +- "member='Released'," +- "path='/org/freedesktop/systemd1/agent'", +- signal_agent_released, m); +- +- if (r < 0) { +- log_warning_errno(r, "Failed to register Released match on new connection bus: %m"); +- return 0; +- } +- } +- + r = bus_setup_disconnected_match(m, bus); + if (r < 0) + return 0; +diff --git a/src/core/dbus.h b/src/core/dbus.h +index d04f532..c27d136 100644 +--- a/src/core/dbus.h ++++ b/src/core/dbus.h +@@ -40,3 +40,5 @@ int bus_verify_manage_unit_async(Manager *m, sd_bus_message *call, sd_bus_error + int bus_verify_manage_unit_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error); + int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error); + int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error); ++ ++int bus_forward_agent_released(Manager *m, const char *path); +diff --git a/src/core/manager.c b/src/core/manager.c +index ee456fb..370c8cb 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -83,8 +83,10 @@ + #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC) + #define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3) + #define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3 ++#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024) + + static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); ++static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); + static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); +@@ -456,11 +458,11 @@ static int manager_setup_signals(Manager *m) { + if (r < 0) + return r; + +- /* Process signals a bit earlier than the rest of things, but +- * later than notify_fd processing, so that the notify +- * processing can still figure out to which process/service a +- * message belongs, before we reap the process. */ +- r = sd_event_source_set_priority(m->signal_event_source, -5); ++ /* Process signals a bit earlier than the rest of things, but later than notify_fd processing, so that the ++ * notify processing can still figure out to which process/service a message belongs, before we reap the ++ * process. Also, process this before handling cgroup notifications, so that we always collect child exit ++ * status information before detecting that there's no process in a cgroup. */ ++ r = sd_event_source_set_priority(m->signal_event_source, -6); + if (r < 0) + return r; + +@@ -541,7 +543,7 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) { + + m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1; + +- m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1; ++ m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1; + m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */ + + m->ask_password_inotify_fd = -1; +@@ -689,8 +691,8 @@ static int manager_setup_notify(Manager *m) { + if (r < 0) + return log_error_errno(r, "Failed to allocate notify event source: %m"); + +- /* Process signals a bit earlier than SIGCHLD, so that we can +- * still identify to which service an exit message belongs */ ++ /* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which ++ * service an exit message belongs. */ + r = sd_event_source_set_priority(m->notify_event_source, -7); + if (r < 0) + return log_error_errno(r, "Failed to set priority of notify event source: %m"); +@@ -699,6 +701,77 @@ static int manager_setup_notify(Manager *m) { + return 0; + } + ++static int manager_setup_cgroups_agent(Manager *m) { ++ ++ static const union sockaddr_union sa = { ++ .un.sun_family = AF_UNIX, ++ .un.sun_path = "/run/systemd/cgroups-agent", ++ }; ++ int r; ++ ++ /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering ++ * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and ++ * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on ++ * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number ++ * of D-Bus connections may be queued until the kernel will start dropping further incoming connections, ++ * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX ++ * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and ++ * we thus won't lose messages. ++ * ++ * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen ++ * to it. The system instance hence listens on this special socket, but the user instances listen on the system ++ * bus for these messages. */ ++ ++ if (m->test_run) ++ return 0; ++ ++ if (!m->running_as == SYSTEMD_SYSTEM) ++ return 0; ++ ++ if (m->cgroups_agent_fd < 0) { ++ _cleanup_close_ int fd = -1; ++ ++ /* First free all secondary fields */ ++ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source); ++ ++ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); ++ if (fd < 0) ++ return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m"); ++ ++ fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE); ++ ++ (void) unlink(sa.un.sun_path); ++ ++ /* Only allow root to connect to this socket */ ++ RUN_WITH_UMASK(0077) ++ r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); ++ if (r < 0) ++ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); ++ ++ m->cgroups_agent_fd = fd; ++ fd = -1; ++ } ++ ++ if (!m->cgroups_agent_event_source) { ++ r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m); ++ if (r < 0) ++ return log_error_errno(r, "Failed to allocate cgroups agent event source: %m"); ++ ++ /* Process cgroups notifications early, but after having processed service notification messages or ++ * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification, ++ * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of ++ * cgroup inotify for the unified cgroup stuff. */ ++ r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5); ++ if (r < 0) ++ return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m"); ++ ++ (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent"); ++ } ++ ++ return 0; ++} ++ ++ + static int manager_setup_kdbus(Manager *m) { + #ifdef ENABLE_KDBUS + _cleanup_free_ char *p = NULL; +@@ -912,6 +985,7 @@ Manager* manager_free(Manager *m) { + + sd_event_source_unref(m->signal_event_source); + sd_event_source_unref(m->notify_event_source); ++ sd_event_source_unref(m->cgroups_agent_event_source); + sd_event_source_unref(m->time_change_event_source); + sd_event_source_unref(m->jobs_in_progress_event_source); + sd_event_source_unref(m->idle_pipe_event_source); +@@ -919,6 +993,7 @@ Manager* manager_free(Manager *m) { + + safe_close(m->signal_fd); + safe_close(m->notify_fd); ++ safe_close(m->cgroups_agent_fd); + safe_close(m->time_change_fd); + safe_close(m->kdbus_fd); + +@@ -1167,6 +1242,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + if (q < 0 && r == 0) + r = q; + ++ q = manager_setup_cgroups_agent(m); ++ if (q < 0 && r == 0) ++ r = q; ++ + /* We might have deserialized the kdbus control fd, but if we + * didn't, then let's create the bus now. */ + manager_setup_kdbus(m); +@@ -1492,6 +1571,35 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { + return n; + } + ++static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { ++ Manager *m = userdata; ++ char buf[PATH_MAX+1]; ++ ssize_t n; ++ ++ n = recv(fd, buf, sizeof(buf), 0); ++ if (n < 0) ++ return log_error_errno(errno, "Failed to read cgroups agent message: %m"); ++ if (n == 0) { ++ log_error("Got zero-length cgroups agent message, ignoring."); ++ return 0; ++ } ++ if ((size_t) n >= sizeof(buf)) { ++ log_error("Got overly long cgroups agent message, ignoring."); ++ return 0; ++ } ++ ++ if (memchr(buf, 0, n)) { ++ log_error("Got cgroups agent message with embedded NUL byte, ignoring."); ++ return 0; ++ } ++ buf[n] = 0; ++ ++ manager_notify_cgroup_empty(m, buf); ++ bus_forward_agent_released(m, buf); ++ ++ return 0; ++} ++ + static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) { + _cleanup_strv_free_ char **tags = NULL; + +@@ -2304,6 +2412,16 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { + fprintf(f, "notify-socket=%s\n", m->notify_socket); + } + ++ if (m->cgroups_agent_fd >= 0) { ++ int copy; ++ ++ copy = fdset_put_dup(fds, m->cgroups_agent_fd); ++ if (copy < 0) ++ return copy; ++ ++ fprintf(f, "cgroups-agent-fd=%i\n", copy); ++ } ++ + if (m->kdbus_fd >= 0) { + int copy; + +@@ -2473,6 +2591,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + free(m->notify_socket); + m->notify_socket = n; + ++ } else if (startswith(l, "cgroups-agent-fd=")) { ++ int fd; ++ ++ if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) ++ log_debug("Failed to parse cgroups agent fd: %s", l + 10); ++ else { ++ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source); ++ safe_close(m->cgroups_agent_fd); ++ m->cgroups_agent_fd = fdset_remove(fds, fd); ++ } ++ + } else if (startswith(l, "kdbus-fd=")) { + int fd; + +@@ -2599,6 +2728,10 @@ int manager_reload(Manager *m) { + if (q < 0 && r >= 0) + r = q; + ++ q = manager_setup_cgroups_agent(m); ++ if (q < 0 && r >= 0) ++ r = q; ++ + /* Third, fire things up! */ + q = manager_coldplug(m); + if (q < 0 && r >= 0) +diff --git a/src/core/manager.h b/src/core/manager.h +index d3971f1..3e855db 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -137,6 +137,9 @@ struct Manager { + int notify_fd; + sd_event_source *notify_event_source; + ++ int cgroups_agent_fd; ++ sd_event_source *cgroups_agent_event_source; ++ + int signal_fd; + sd_event_source *signal_event_source; + diff --git a/SOURCES/0330-logind-process-session-inhibitor-fds-at-higher-prior.patch b/SOURCES/0330-logind-process-session-inhibitor-fds-at-higher-prior.patch new file mode 100644 index 0000000..74225fe --- /dev/null +++ b/SOURCES/0330-logind-process-session-inhibitor-fds-at-higher-prior.patch @@ -0,0 +1,59 @@ +From caca204d23babbdb0c688f543f3ee8d66a1a2001 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 4 May 2016 19:01:56 +0200 +Subject: [PATCH] logind: process session/inhibitor fds at higher priority + +Let's make sure we process session and inhibitor pipe fds (that signal +sessions/inhibtors going away) at a higher priority +than new bus calls that might create new sessions or inhibitors. This helps +ensuring that the number of open sessions stays minimal. + +Cherry-picked from: e11544a8305ab9dea097c74bb16e296150c9cc10 +Resolves: #1305608 +--- + src/login/logind-inhibit.c | 2 +- + src/login/logind-session.c | 4 +++- + src/login/logind.c | 2 +- + 3 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c +index 84fee0e..bf96898 100644 +--- a/src/login/logind-inhibit.c ++++ b/src/login/logind-inhibit.c +@@ -303,7 +303,7 @@ int inhibitor_create_fifo(Inhibitor *i) { + if (r < 0) + return r; + +- r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE); ++ r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10); + if (r < 0) + return r; + } +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index dc24539..59f5a7a 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -905,7 +905,9 @@ int session_create_fifo(Session *s) { + if (r < 0) + return r; + +- r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE); ++ /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new ++ * sessions). */ ++ r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10); + if (r < 0) + return r; + } +diff --git a/src/login/logind.c b/src/login/logind.c +index 3afbf34..e8d0669 100644 +--- a/src/login/logind.c ++++ b/src/login/logind.c +@@ -685,7 +685,7 @@ static int manager_connect_bus(Manager *m) { + if (r < 0) + return log_error_errno(r, "Failed to register name: %m"); + +- r = sd_bus_attach_event(m->bus, m->event, 0); ++ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) + return log_error_errno(r, "Failed to attach bus to event loop: %m"); + diff --git a/SOURCES/0331-Teach-bus_append_unit_property_assignment-about-Dele.patch b/SOURCES/0331-Teach-bus_append_unit_property_assignment-about-Dele.patch new file mode 100644 index 0000000..39ce2f4 --- /dev/null +++ b/SOURCES/0331-Teach-bus_append_unit_property_assignment-about-Dele.patch @@ -0,0 +1,27 @@ +From f44296a5324dc84ff1b2a82bd1dd2d47160762b5 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 23 May 2016 14:51:12 +0200 +Subject: [PATCH] Teach bus_append_unit_property_assignment() about 'Delegate' + property + +"Cherry-picked" from ea1a971646d31b990190f473c5c7e3562f36d3c9. + +Resolves: #1337922 +--- + src/libsystemd/sd-bus/bus-util.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 3a91836..9d70798 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1388,7 +1388,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + + if (STR_IN_SET(field, + "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", +- "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies")) { ++ "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", ++ "Delegate")) { + + r = parse_boolean(eq); + if (r < 0) { diff --git a/SOURCES/0332-sd-netlink-fix-deep-recursion-in-message-destruction.patch b/SOURCES/0332-sd-netlink-fix-deep-recursion-in-message-destruction.patch new file mode 100644 index 0000000..633bb16 --- /dev/null +++ b/SOURCES/0332-sd-netlink-fix-deep-recursion-in-message-destruction.patch @@ -0,0 +1,47 @@ +From 164a98ea6b24fea3433516dcc0df496929674cdd Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 7 Jun 2016 12:43:38 +0200 +Subject: [PATCH] sd-netlink: fix deep recursion in message destruction + +On larger systems we might very well see messages with thousands of parts. +When we free them, we must avoid recursing into each part, otherwise we +very likely get stack overflows. + +Fix sd_netlink_message_unref() to use an iterative approach rather than +recursion (also avoid tail-recursion in case it is not optimized by the +compiler). + +(cherry picked from commit 82e4eda664d40ef60829e27d84b1610c2f4070cd) +Resolves: #1330593 +--- + src/libsystemd/sd-rtnl/rtnl-message.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c +index 276591f..9276bbd 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-message.c ++++ b/src/libsystemd/sd-rtnl/rtnl-message.c +@@ -584,7 +584,9 @@ sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) { + } + + sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) { +- if (m && REFCNT_DEC(m->n_ref) == 0) { ++ sd_rtnl_message *t; ++ ++ while (m && REFCNT_DEC(m->n_ref) == 0) { + unsigned i; + + free(m->hdr); +@@ -592,9 +594,9 @@ sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) { + for (i = 0; i <= m->n_containers; i++) + free(m->rta_offset_tb[i]); + +- sd_rtnl_message_unref(m->next); +- +- free(m); ++ t = m; ++ m = m->next; ++ free(t); + } + + return NULL; diff --git a/SOURCES/0333-add-REMOTE_ADDR-and-REMOTE_PORT-for-Accept-yes.patch b/SOURCES/0333-add-REMOTE_ADDR-and-REMOTE_PORT-for-Accept-yes.patch new file mode 100644 index 0000000..11a75b3 --- /dev/null +++ b/SOURCES/0333-add-REMOTE_ADDR-and-REMOTE_PORT-for-Accept-yes.patch @@ -0,0 +1,281 @@ +From afa96dafde9d50f2b53ccf8136ead9ed79544877 Mon Sep 17 00:00:00 2001 +From: Shawn Landden +Date: Tue, 10 Mar 2015 04:41:59 -0700 +Subject: [PATCH] add REMOTE_ADDR and REMOTE_PORT for Accept=yes + +Cherry-picked from: 3b1c524154c876aecebc98787975cc2943100210 +Resolves: #1341154 +--- + TODO | 2 - + man/systemd.socket.xml | 7 ++- + src/core/service.c | 42 +++++++++++++++++- + src/libsystemd/sd-resolve/test-resolve.c | 2 +- + src/shared/socket-util.c | 76 +++++++++++++++++++++++--------- + src/shared/socket-util.h | 4 +- + src/timesync/timesyncd-server.h | 2 +- + 7 files changed, 107 insertions(+), 28 deletions(-) + +diff --git a/TODO b/TODO +index d96d2bf..498d82c 100644 +--- a/TODO ++++ b/TODO +@@ -185,8 +185,6 @@ Features: + * as soon as we have kdbus, and sender timestamps, revisit coalescing multiple parallel daemon reloads: + http://lists.freedesktop.org/archives/systemd-devel/2014-December/025862.html + +-* set $REMOTE_IP (or $REMOTE_ADDR/$REMOTE_PORT) environment variable when doing per-connection socket activation. use format introduced by xinetd or CGI for this +- + * the install state probably shouldn't get confused by generated units, think dbus1/kdbus compat! + + * in systemctl list-unit-files: show the install value the presets would suggest for a service in a third column +diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml +index 2f54193..350a956 100644 +--- a/man/systemd.socket.xml ++++ b/man/systemd.socket.xml +@@ -357,7 +357,12 @@ + daemons designed for usage with + inetd8 + to work unmodified with systemd socket +- activation. ++ activation. ++ ++ For IPv4 and IPv6 connections the REMOTE_ADDR ++ environment variable will contain the remote IP, and REMOTE_PORT ++ will contain the remote port. This is the same as the format used by CGI. ++ For SOCK_RAW the port is the IP protocol. + + + +diff --git a/src/core/service.c b/src/core/service.c +index ae5e610..c76713b 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -1094,7 +1094,7 @@ static int service_spawn( + if (r < 0) + goto fail; + +- our_env = new0(char*, 4); ++ our_env = new0(char*, 6); + if (!our_env) { + r = -ENOMEM; + goto fail; +@@ -1118,6 +1118,46 @@ static int service_spawn( + goto fail; + } + ++ if (UNIT_DEREF(s->accept_socket)) { ++ union sockaddr_union sa; ++ socklen_t salen = sizeof(sa); ++ ++ r = getpeername(s->socket_fd, &sa.sa, &salen); ++ if (r < 0) { ++ r = -errno; ++ goto fail; ++ } ++ ++ if (IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) { ++ _cleanup_free_ char *addr = NULL; ++ char *t; ++ int port; ++ ++ r = sockaddr_pretty(&sa.sa, salen, true, false, &addr); ++ if (r < 0) ++ goto fail; ++ ++ t = strappend("REMOTE_ADDR=", addr); ++ if (!t) { ++ r = -ENOMEM; ++ goto fail; ++ } ++ our_env[n_env++] = t; ++ ++ port = sockaddr_port(&sa.sa); ++ if (port < 0) { ++ r = port; ++ goto fail; ++ } ++ ++ if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) { ++ r = -ENOMEM; ++ goto fail; ++ } ++ our_env[n_env++] = t; ++ } ++ } ++ + final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL); + if (!final_env) { + r = -ENOMEM; +diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c +index d08e1b5..a14b6de 100644 +--- a/src/libsystemd/sd-resolve/test-resolve.c ++++ b/src/libsystemd/sd-resolve/test-resolve.c +@@ -49,7 +49,7 @@ static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrin + for (i = ai; i; i = i->ai_next) { + _cleanup_free_ char *addr = NULL; + +- assert_se(sockaddr_pretty(i->ai_addr, i->ai_addrlen, false, &addr) == 0); ++ assert_se(sockaddr_pretty(i->ai_addr, i->ai_addrlen, false, true, &addr) == 0); + puts(addr); + } + +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index 407d0af..a212510 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -302,7 +302,7 @@ int socket_address_print(const SocketAddress *a, char **ret) { + return 0; + } + +- return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret); ++ return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret); + } + + bool socket_address_can_accept(const SocketAddress *a) { +@@ -471,7 +471,20 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { + return socket_address_equal(a, &b); + } + +-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) { ++int sockaddr_port(const struct sockaddr *_sa) { ++ union sockaddr_union *sa = (union sockaddr_union*) _sa; ++ ++ assert(sa); ++ ++ if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6)) ++ return -EAFNOSUPPORT; ++ ++ return ntohs(sa->sa.sa_family == AF_INET6 ? ++ sa->in6.sin6_port : ++ sa->in.sin_port); ++} ++ ++int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) { + union sockaddr_union *sa = (union sockaddr_union*) _sa; + char *p; + +@@ -485,11 +498,18 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ + + a = ntohl(sa->in.sin_addr.s_addr); + +- if (asprintf(&p, +- "%u.%u.%u.%u:%u", +- a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, +- ntohs(sa->in.sin_port)) < 0) +- return -ENOMEM; ++ if (include_port) { ++ if (asprintf(&p, ++ "%u.%u.%u.%u:%u", ++ a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF, ++ ntohs(sa->in.sin_port)) < 0) ++ return -ENOMEM; ++ } else { ++ if (asprintf(&p, ++ "%u.%u.%u.%u", ++ a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF) < 0) ++ return -ENOMEM; ++ } + + break; + } +@@ -501,20 +521,34 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ + + if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) { + const uint8_t *a = sa->in6.sin6_addr.s6_addr+12; +- +- if (asprintf(&p, +- "%u.%u.%u.%u:%u", +- a[0], a[1], a[2], a[3], +- ntohs(sa->in6.sin6_port)) < 0) +- return -ENOMEM; ++ if (include_port) { ++ if (asprintf(&p, ++ "%u.%u.%u.%u:%u", ++ a[0], a[1], a[2], a[3], ++ ntohs(sa->in6.sin6_port)) < 0) ++ return -ENOMEM; ++ } else { ++ if (asprintf(&p, ++ "%u.%u.%u.%u", ++ a[0], a[1], a[2], a[3]) < 0) ++ return -ENOMEM; ++ } + } else { + char a[INET6_ADDRSTRLEN]; + +- if (asprintf(&p, +- "[%s]:%u", +- inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)), +- ntohs(sa->in6.sin6_port)) < 0) +- return -ENOMEM; ++ inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)); ++ ++ if (include_port) { ++ if (asprintf(&p, ++ "[%s]:%u", ++ a, ++ ntohs(sa->in6.sin6_port)) < 0) ++ return -ENOMEM; ++ } else { ++ p = strdup(a); ++ if (!p) ++ return -ENOMEM; ++ } + } + + break; +@@ -589,7 +623,7 @@ int getpeername_pretty(int fd, char **ret) { + /* For remote sockets we translate IPv6 addresses back to IPv4 + * if applicable, since that's nicer. */ + +- return sockaddr_pretty(&sa.sa, salen, true, ret); ++ return sockaddr_pretty(&sa.sa, salen, true, true, ret); + } + + int getsockname_pretty(int fd, char **ret) { +@@ -607,7 +641,7 @@ int getsockname_pretty(int fd, char **ret) { + * listening sockets where the difference between IPv4 and + * IPv6 matters. */ + +- return sockaddr_pretty(&sa.sa, salen, false, ret); ++ return sockaddr_pretty(&sa.sa, salen, false, true, ret); + } + + int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) { +@@ -621,7 +655,7 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) + if (r != 0) { + int saved_errno = errno; + +- r = sockaddr_pretty(&sa->sa, salen, true, &ret); ++ r = sockaddr_pretty(&sa->sa, salen, true, true, &ret); + if (r < 0) + return log_error_errno(r, "sockadd_pretty() failed: %m"); + +diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h +index 07d0aff..6bfb677 100644 +--- a/src/shared/socket-util.h ++++ b/src/shared/socket-util.h +@@ -98,7 +98,9 @@ const char* socket_address_get_path(const SocketAddress *a); + + bool socket_ipv6_is_supported(void); + +-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret); ++int sockaddr_port(const struct sockaddr *_sa) _pure_; ++ ++int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret); + int getpeername_pretty(int fd, char **ret); + int getsockname_pretty(int fd, char **ret); + +diff --git a/src/timesync/timesyncd-server.h b/src/timesync/timesyncd-server.h +index 243b44a..18c4444 100644 +--- a/src/timesync/timesyncd-server.h ++++ b/src/timesync/timesyncd-server.h +@@ -59,7 +59,7 @@ struct ServerName { + int server_address_new(ServerName *n, ServerAddress **ret, const union sockaddr_union *sockaddr, socklen_t socklen); + ServerAddress* server_address_free(ServerAddress *a); + static inline int server_address_pretty(ServerAddress *a, char **pretty) { +- return sockaddr_pretty(&a->sockaddr.sa, a->socklen, true, pretty); ++ return sockaddr_pretty(&a->sockaddr.sa, a->socklen, true, true, pretty); + } + + int server_name_new(Manager *m, ServerName **ret, ServerType type,const char *string); diff --git a/SOURCES/0334-core-don-t-dispatch-load-queue-when-setting-Slice-fo.patch b/SOURCES/0334-core-don-t-dispatch-load-queue-when-setting-Slice-fo.patch new file mode 100644 index 0000000..005f4a8 --- /dev/null +++ b/SOURCES/0334-core-don-t-dispatch-load-queue-when-setting-Slice-fo.patch @@ -0,0 +1,37 @@ +From b3207925388c6423a7665b9363eea90f41a30576 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Apr 2016 17:30:08 +0200 +Subject: [PATCH] core: don't dispatch load queue when setting Slice= for + transient units + +Let's be more careful when setting up the Slice= property of transient units: +let's use manager_load_unit_prepare() instead of manager_load_unit(), so that +the load queue isn't dispatched right away, because our own transient unit is +in it, and we don#t want to have it loaded until we finished initializing it. + +(cherry picked from commit aea529e5b2c864d536941ee18220abcc1a9015a0) +Resolves: #1343904 +--- + src/core/dbus-unit.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 227915e..49770bf 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -930,10 +930,14 @@ static int bus_unit_set_transient_property( + } else { + Unit *slice; + +- r = manager_load_unit(u->manager, s, NULL, error, &slice); ++ /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be ++ * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare() ++ * instead of manager_load_unit() on purpose, here. */ ++ r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice); + if (r < 0) + return r; + ++ + if (slice->type != UNIT_SLICE) + return -EINVAL; + diff --git a/SOURCES/0335-run-make-slice-work-in-conjunction-with-scope.patch b/SOURCES/0335-run-make-slice-work-in-conjunction-with-scope.patch new file mode 100644 index 0000000..a9b279e --- /dev/null +++ b/SOURCES/0335-run-make-slice-work-in-conjunction-with-scope.patch @@ -0,0 +1,27 @@ +From 735f6a0d81b4bbefd0cb57bbfd51f0f86e4a703e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 22 Apr 2016 17:31:40 +0200 +Subject: [PATCH] run: make --slice= work in conjunction with --scope + +Fixes: #2991 +(cherry picked from commit 37e605f934892bf7458eecaeb01fc682e33cc2ad) +Resolves: #1343904 +--- + src/run/run.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/run/run.c b/src/run/run.c +index 4680342..bbb542b 100644 +--- a/src/run/run.c ++++ b/src/run/run.c +@@ -595,6 +595,10 @@ static int transient_scope_set_properties(sd_bus_message *m) { + if (r < 0) + return r; + ++ r = transient_cgroup_set_properties(m); ++ if (r < 0) ++ return r; ++ + r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid()); + if (r < 0) + return r; diff --git a/SOURCES/0336-myhostname-fix-timeout-if-ipv6-is-disabled.patch b/SOURCES/0336-myhostname-fix-timeout-if-ipv6-is-disabled.patch new file mode 100644 index 0000000..e1d7450 --- /dev/null +++ b/SOURCES/0336-myhostname-fix-timeout-if-ipv6-is-disabled.patch @@ -0,0 +1,61 @@ +From 6e5117b83af5998359916f276a9b32f755c0e6f4 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 20 May 2016 12:33:48 +0200 +Subject: [PATCH] myhostname: fix timeout if ipv6 is disabled + +rhel-only +Resolves: #1330973 +--- + src/nss-myhostname/nss-myhostname.c | 9 +++++++-- + src/shared/socket-util.c | 10 ++++++++++ + 2 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c +index a939bb2..e197cc7 100644 +--- a/src/nss-myhostname/nss-myhostname.c ++++ b/src/nss-myhostname/nss-myhostname.c +@@ -33,6 +33,7 @@ + #include "local-addresses.h" + #include "macro.h" + #include "nss-util.h" ++#include "socket-util.h" + #include "util.h" + + /* We use 127.0.0.2 as IPv4 address. This has the advantage over +@@ -380,9 +381,13 @@ enum nss_status _nss_myhostname_gethostbyname3_r( + return NSS_STATUS_NOTFOUND; + } + +- n_addresses = local_addresses(NULL, 0, af, &addresses); +- if (n_addresses < 0) ++ if (af == AF_INET6 && !socket_ipv6_is_supported()) { + n_addresses = 0; ++ } else { ++ n_addresses = local_addresses(NULL, 0, af, &addresses); ++ if (n_addresses < 0) ++ n_addresses = 0; ++ } + + canonical = hn; + additional = n_addresses <= 0 && af == AF_INET6 ? "localhost" : NULL; +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index a212510..79d1582 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -435,6 +435,16 @@ bool socket_ipv6_is_supported(void) { + return true; + + /* If module was loaded with disable=1 no IPv6 available */ ++ if (l[0] == '1') ++ return false; ++ ++ free(l); ++ l = NULL; ++ ++ if (read_one_line_file("/proc/sys/net/ipv6/conf/all/disable_ipv6", &l) < 0) ++ return true; ++ ++ /* If IPv6 was disabled via sysctl during runtime */ + return l[0] == '0'; + } + diff --git a/SOURCES/0337-readahead-do-not-increase-nr_requests-for-root-fs-bl.patch b/SOURCES/0337-readahead-do-not-increase-nr_requests-for-root-fs-bl.patch new file mode 100644 index 0000000..1bca28f --- /dev/null +++ b/SOURCES/0337-readahead-do-not-increase-nr_requests-for-root-fs-bl.patch @@ -0,0 +1,124 @@ +From 997778e332e9f6d3d1c42e9a222fcab8d4732c40 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 27 May 2016 14:29:17 +0200 +Subject: [PATCH] readahead: do not increase nr_requests for root fs block + device + +Having nr_requests can cause system lockups. Arguably, this should get +fixed somehow in kernel. For now we just stop changing the +value. + +Note that not bumping a value may cause that posix_fadvise call +will block in case there is no room in a request queue. + +See: http://article.gmane.org/gmane.linux.kernel/1072356 + +RHEL-only +Resolves: #1314559 +--- + src/readahead/readahead-common.c | 64 ---------------------------------------- + src/readahead/readahead-common.h | 2 -- + src/readahead/readahead-replay.c | 2 -- + 3 files changed, 68 deletions(-) + +diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c +index 3ca48a7..6cf33f7 100644 +--- a/src/readahead/readahead-common.c ++++ b/src/readahead/readahead-common.c +@@ -253,70 +253,6 @@ ReadaheadShared *shared_get(void) { + return m; + } + +-/* We use 20K instead of the more human digestable 16K here. Why? +- Simply so that it is more unlikely that users end up picking this +- value too so that we can recognize better whether the user changed +- the value while we had it temporarily bumped. */ +-#define BUMP_REQUEST_NR (20*1024u) +- +-int block_bump_request_nr(const char *p) { +- struct stat st; +- uint64_t u; +- char *ap = NULL, *line = NULL; +- int r; +- dev_t d; +- +- assert(p); +- +- if (stat(p, &st) < 0) +- return -errno; +- +- if (major(st.st_dev) == 0) +- return 0; +- +- d = st.st_dev; +- block_get_whole_disk(d, &d); +- +- if (asprintf(&ap, "/sys/dev/block/%u:%u/queue/nr_requests", major(d), minor(d)) < 0) { +- r= -ENOMEM; +- goto finish; +- } +- +- r = read_one_line_file(ap, &line); +- if (r < 0) { +- if (r == -ENOENT) +- r = 0; +- goto finish; +- } +- +- r = safe_atou64(line, &u); +- if (r >= 0 && u >= BUMP_REQUEST_NR) { +- r = 0; +- goto finish; +- } +- +- free(line); +- line = NULL; +- +- if (asprintf(&line, "%u", BUMP_REQUEST_NR) < 0) { +- r = -ENOMEM; +- goto finish; +- } +- +- r = write_string_file(ap, line); +- if (r < 0) +- goto finish; +- +- log_info("Bumped block_nr parameter of %u:%u to %u. This is a temporary hack and should be removed one day.", major(d), minor(d), BUMP_REQUEST_NR); +- r = 1; +- +-finish: +- free(ap); +- free(line); +- +- return r; +-} +- + int block_get_readahead(const char *p, uint64_t *bytes) { + struct stat st; + char *ap = NULL, *line = NULL; +diff --git a/src/readahead/readahead-common.h b/src/readahead/readahead-common.h +index b34f3aa..cc2ea81 100644 +--- a/src/readahead/readahead-common.h ++++ b/src/readahead/readahead-common.h +@@ -51,8 +51,6 @@ typedef struct ReadaheadShared { + + ReadaheadShared *shared_get(void); + +-int block_bump_request_nr(const char *p); +- + int block_get_readahead(const char *p, uint64_t *bytes); + int block_set_readahead(const char *p, uint64_t bytes); + +diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c +index f81e0fe..c2e2816 100644 +--- a/src/readahead/readahead-replay.c ++++ b/src/readahead/readahead-replay.c +@@ -134,8 +134,6 @@ static int replay(const char *root) { + + assert(root); + +- block_bump_request_nr(root); +- + if (asprintf(&pack_fn, "%s/.readahead", root) < 0) + return log_oom(); + diff --git a/SOURCES/0338-manager-reduce-complexity-of-unit_gc_sweep-3507.patch b/SOURCES/0338-manager-reduce-complexity-of-unit_gc_sweep-3507.patch new file mode 100644 index 0000000..24530fd --- /dev/null +++ b/SOURCES/0338-manager-reduce-complexity-of-unit_gc_sweep-3507.patch @@ -0,0 +1,62 @@ +From 33ca0f1f0d4b9a91588c84067d2fb30968e41235 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Tue, 14 Jun 2016 14:20:56 +0200 +Subject: [PATCH] manager: reduce complexity of unit_gc_sweep (#3507) + +When unit is marked as UNSURE, we are trying to find if it state was +changed over and over again. So lets not go through the UNSURE states +again. Also when we find a GOOD unit lets propagate the GOOD state to +all units that this unit reference. + +This is a problem on machines with a lot of initscripts with different +starting priority, since those units will reference each other and the +original algorithm might get to n! complexity. + +Thanks HATAYAMA Daisuke for the expand_good_state code. +Cherry-picked from: 4892084f096c19da0e83f28f250ca187b58c22b2 +Resolves: #1344556 +--- + src/core/manager.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 370c8cb..e5226a8 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -838,6 +838,19 @@ enum { + _GC_OFFSET_MAX + }; + ++static void unit_gc_mark_good(Unit *u, unsigned gc_marker) ++{ ++ Iterator i; ++ Unit *other; ++ ++ u->gc_marker = gc_marker + GC_OFFSET_GOOD; ++ ++ /* Recursively mark referenced units as GOOD as well */ ++ SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i) ++ if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE) ++ unit_gc_mark_good(other, gc_marker); ++} ++ + static void unit_gc_sweep(Unit *u, unsigned gc_marker) { + Iterator i; + Unit *other; +@@ -847,6 +860,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) { + + if (u->gc_marker == gc_marker + GC_OFFSET_GOOD || + u->gc_marker == gc_marker + GC_OFFSET_BAD || ++ u->gc_marker == gc_marker + GC_OFFSET_UNSURE || + u->gc_marker == gc_marker + GC_OFFSET_IN_PATH) + return; + +@@ -887,7 +901,7 @@ bad: + return; + + good: +- u->gc_marker = gc_marker + GC_OFFSET_GOOD; ++ unit_gc_mark_good(u, gc_marker); + } + + static unsigned manager_dispatch_gc_queue(Manager *m) { diff --git a/SOURCES/0339-hwdb-selinuxify-a-bit-3460.patch b/SOURCES/0339-hwdb-selinuxify-a-bit-3460.patch new file mode 100644 index 0000000..c98059d --- /dev/null +++ b/SOURCES/0339-hwdb-selinuxify-a-bit-3460.patch @@ -0,0 +1,68 @@ +From ca82178b166ae5fb8efe4b09aadae802534cf6e3 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Tue, 7 Jun 2016 20:47:41 +0300 +Subject: [PATCH] hwdb: selinuxify a bit (#3460) + +-bash-4.3# rm /etc/udev/hwdb.bin +-bash-4.3# systemd-hwdb update +-bash-4.3# ls -Z /etc/udev/hwdb.bin +system_u:object_r:systemd_hwdb_etc_t:s0 /etc/udev/hwdb.bin + +Fixes: #3458 + +(cherry picked from commit ea683512f9b82f2257770f0ed56d819eea230fc2) +Resolves: #1343648 +--- + Makefile.am | 1 + + src/hwdb/hwdb.c | 8 ++++++-- + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index b0a34b2..3848338 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3752,6 +3752,7 @@ systemd_hwdb_SOURCES = \ + src/hwdb/hwdb.c + + systemd_hwdb_LDADD = \ ++ libsystemd-label.la \ + libsystemd-shared.la \ + libsystemd-internal.la \ + libudev-internal.la +diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c +index 4539673..8e5d6cc 100644 +--- a/src/hwdb/hwdb.c ++++ b/src/hwdb/hwdb.c +@@ -34,6 +34,8 @@ + + #include "hwdb-internal.h" + #include "hwdb-util.h" ++#include "label.h" ++#include "selinux-util.h" + + /* + * Generic udev properties, key/value database based on modalias strings. +@@ -642,12 +644,12 @@ static int hwdb_update(int argc, char *argv[], void *userdata) { + if (!hwdb_bin) + return -ENOMEM; + +- mkdir_parents(hwdb_bin, 0755); ++ mkdir_parents_label(hwdb_bin, 0755); + r = trie_store(trie, hwdb_bin); + if (r < 0) + return log_error_errno(r, "Failure writing database %s: %m", hwdb_bin); + +- return 0; ++ return label_fix(hwdb_bin, false, false); + } + + static void help(void) { +@@ -733,6 +735,8 @@ int main (int argc, char *argv[]) { + if (r <= 0) + goto finish; + ++ mac_selinux_init(NULL); ++ + r = hwdb_main(argc, argv); + + finish: diff --git a/SOURCES/0340-udevadm-explicitly-relabel-etc-udev-hwdb.bin-after-r.patch b/SOURCES/0340-udevadm-explicitly-relabel-etc-udev-hwdb.bin-after-r.patch new file mode 100644 index 0000000..6374256 --- /dev/null +++ b/SOURCES/0340-udevadm-explicitly-relabel-etc-udev-hwdb.bin-after-r.patch @@ -0,0 +1,55 @@ +From 0860805a09ce6c2c2136306bdf64d58621368291 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 8 Jul 2016 15:54:55 +0200 +Subject: [PATCH] udevadm: explicitly relabel /etc/udev/hwdb.bin after rename + +This is basically the same change as ea68351. + +Cherry-picked from: 4f43161e909cb420aafbc4bebce4361b17b80fdd +Related: #1350756 +--- + src/udev/udevadm-hwdb.c | 5 ++++- + src/udev/udevadm.c | 2 +- + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c +index d65e40c..201e2a0 100644 +--- a/src/udev/udevadm-hwdb.c ++++ b/src/udev/udevadm-hwdb.c +@@ -26,6 +26,8 @@ + #include "util.h" + #include "strbuf.h" + #include "conf-files.h" ++#include "label.h" ++#include "mkdir.h" + + #include "udev.h" + #include "hwdb-internal.h" +@@ -654,12 +656,13 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { + rc = EXIT_FAILURE; + goto out; + } +- mkdir_parents(hwdb_bin, 0755); ++ mkdir_parents_label(hwdb_bin, 0755); + err = trie_store(trie, hwdb_bin); + if (err < 0) { + log_error_errno(err, "Failure writing database %s: %m", hwdb_bin); + rc = EXIT_FAILURE; + } ++ label_fix(hwdb_bin, false, false); + } + + if (test) { +diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c +index 56cd0cd..d05a26e 100644 +--- a/src/udev/udevadm.c ++++ b/src/udev/udevadm.c +@@ -96,7 +96,7 @@ int main(int argc, char *argv[]) { + + log_parse_environment(); + log_open(); +- mac_selinux_init("/dev"); ++ mac_selinux_init(NULL); + + while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0) + switch (c) { diff --git a/SOURCES/0341-systemctl-return-diffrent-error-code-if-service-exis.patch b/SOURCES/0341-systemctl-return-diffrent-error-code-if-service-exis.patch new file mode 100644 index 0000000..84b59cb --- /dev/null +++ b/SOURCES/0341-systemctl-return-diffrent-error-code-if-service-exis.patch @@ -0,0 +1,82 @@ +From 2eb2ddac8eaa258dd1ac0b2d4c1aefef9b66a989 Mon Sep 17 00:00:00 2001 +From: Susant Sahani +Date: Mon, 30 May 2016 20:23:15 +0530 +Subject: [PATCH] systemctl: return diffrent error code if service exist or not + (#3385) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Before: +[sus@maximus bz-1256858]$ systemctl status rsyslog.service;echo $? +● rsyslog.service - System Logging Service + Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor +preset: enabled) + Drop-In: /etc/systemd/system/rsyslog.service.d + └─50-CPUShares.conf + Active: inactive (dead) since Mon 2016-05-30 11:54:25 IST; 2h 26min ago + Docs: man:rsyslogd(8) + http://www.rsyslog.com/doc/ + Process: 1159 ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS (code=exited, +status=0/SUCCESS) + Main PID: 1159 (code=exited, status=0/SUCCESS) + +May 30 11:07:50 maximus systemd[1]: Starting System Logging Service... +May 30 11:07:50 maximus systemd[1]: Started System Logging Service. +May 30 11:54:25 maximus systemd[1]: Stopping System Logging Service... +May 30 11:54:25 maximus systemd[1]: Stopped System Logging Service. +3 +[sus@maximus bz-1256858]$ systemctl status hello.service;echo $? +● hello.service + Loaded: not-found (Reason: No such file or directory) + Active: inactive (dead) +3 + +After: +$ ./systemctl status hello.service;echo $? +Failed to dump process list, ignoring: Access denied +● hello.service + Loaded: not-found (Reason: No such file or directory) + Active: inactive (dead) +4 +[sus@maximus bz-1256858]$ ./systemctl status rsyslog.service;echo $? +Failed to dump process list, ignoring: Access denied +● rsyslog.service - System Logging Service + Loaded: loaded (/usr/lib/systemd/system/rsyslog.service; enabled; vendor +preset: enabled) + Drop-In: /etc/systemd/system/rsyslog.service.d + └─50-CPUShares.conf + Active: inactive (dead) since Mon 2016-05-30 11:54:25 IST; 2h 24min ago + Docs: man:rsyslogd(8) + http://www.rsyslog.com/doc/ + Process: 1159 ExecStart=/usr/sbin/rsyslogd -n $SYSLOGD_OPTIONS (code=exited, +status=0/SUCCESS) + Main PID: 1159 (code=exited, status=0/SUCCESS) + +May 30 11:07:50 maximus systemd[1]: Starting System Logging Service... +May 30 11:07:50 maximus systemd[1]: Started System Logging Service. +May 30 11:54:25 maximus systemd[1]: Stopping System Logging Service... +May 30 11:54:25 maximus systemd[1]: Stopped System Logging Service. +3 + +Fixes: 1092 + +(cherry picked from commit ca473d572f0d2d8f547ff787ae67afd489a3f15e) +Resolves: #1047466 +--- + src/systemctl/systemctl.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 95ddf3b..6079d60 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4295,6 +4295,8 @@ static int show_one( + */ + if (info.pid_file && access(info.pid_file, F_OK) == 0) + r = 1; ++ else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) ++ r = 4; + else + r = 3; + } diff --git a/SOURCES/0342-systemctl-Replace-init-script-error-codes-with-enum-.patch b/SOURCES/0342-systemctl-Replace-init-script-error-codes-with-enum-.patch new file mode 100644 index 0000000..8696946 --- /dev/null +++ b/SOURCES/0342-systemctl-Replace-init-script-error-codes-with-enum-.patch @@ -0,0 +1,74 @@ +From 20a914f752898aae11708d7bf901e7dc1e81a28e Mon Sep 17 00:00:00 2001 +From: Susant Sahani +Date: Tue, 31 May 2016 19:06:58 +0530 +Subject: [PATCH] systemctl: Replace init script error codes with enum (#3400) + +Now we just using constants for the init script exit status codes. +Replace those error codes with enum so that it's more meaningful +and readable. + +(cherry picked from commit b613907ea988e2994c68be686b5e92cdc7d3fb68) +Related: #1047466 +--- + src/systemctl/systemctl.c | 29 ++++++++++++++++++++++++----- + 1 file changed, 24 insertions(+), 5 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 6079d60..fdda174 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -75,6 +75,25 @@ + #include "mkdir.h" + #include "dropin.h" + ++/* The init script exit status codes ++ 0 program is running or service is OK ++ 1 program is dead and /var/run pid file exists ++ 2 program is dead and /var/lock lock file exists ++ 3 program is not running ++ 4 program or service status is unknown ++ 5-99 reserved for future LSB use ++ 100-149 reserved for distribution use ++ 150-199 reserved for application use ++ 200-254 reserved ++*/ ++enum { ++ EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0, ++ EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1, ++ EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2, ++ EXIT_PROGRAM_NOT_RUNNING = 3, ++ EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4, ++}; ++ + static char **arg_types = NULL; + static char **arg_states = NULL; + static char **arg_properties = NULL; +@@ -3028,11 +3047,11 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch + + static int check_unit_active(sd_bus *bus, char **args) { + /* According to LSB: 3, "program is not running" */ +- return check_unit_generic(bus, 3, "active\0reloading\0", args + 1); ++ return check_unit_generic(bus, EXIT_PROGRAM_NOT_RUNNING, "active\0reloading\0", args + 1); + } + + static int check_unit_failed(sd_bus *bus, char **args) { +- return check_unit_generic(bus, 1, "failed\0", args + 1); ++ return check_unit_generic(bus, EXIT_PROGRAM_DEAD_AND_PID_EXISTS, "failed\0", args + 1); + } + + static int kill_unit(sd_bus *bus, char **args) { +@@ -4294,11 +4313,11 @@ static int show_one( + * 4: program or service status is unknown + */ + if (info.pid_file && access(info.pid_file, F_OK) == 0) +- r = 1; ++ r = EXIT_PROGRAM_DEAD_AND_PID_EXISTS; + else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) +- r = 4; ++ r = EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; + else +- r = 3; ++ r = EXIT_PROGRAM_NOT_RUNNING; + } + + while ((p = info.exec)) { diff --git a/SOURCES/0343-systemctl-rework-systemctl-status-a-bit.patch b/SOURCES/0343-systemctl-rework-systemctl-status-a-bit.patch new file mode 100644 index 0000000..21a9c9f --- /dev/null +++ b/SOURCES/0343-systemctl-rework-systemctl-status-a-bit.patch @@ -0,0 +1,234 @@ +From 41bb37959c96b8fddc13b37384b3453393517f4f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 13 Jun 2016 19:11:26 +0200 +Subject: [PATCH] systemctl: rework "systemctl status" a bit + +This reworks "systemctl status" and "systemctl show" a bit. It removes the +definition of the `property_info` structure, because we can simply reuse the +existing UnitStatusInfo type for that. + +The "could not be found" message is now printed by show_one() itself (and not +its caller), so that it is shown regardless by who the function is called. +(This makes it necessary to pass the unit name to the function.) + +This also adds all properties found to a set, and then checks if any of the +properties passed via "--property=" is mising in it, if so, a proper error is +generated. + +Support for checking the PID file of a unit is removed, as this cannot be done +reasonably client side (since the systemd instance we are talking to might sit +on another host) + +Replaces: #3411 +Fixes: #3425 +Also see: #3504 + +(cherry picked from commit 3dced37b7c2c9a5c733817569d2bbbaa397adaf7) +Related: #1047466 +--- + src/systemctl/systemctl.c | 106 +++++++++++++++++++++++++++++----------------- + 1 file changed, 68 insertions(+), 38 deletions(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index fdda174..93b7a19 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4211,12 +4211,19 @@ static int show_one( + const char *verb, + sd_bus *bus, + const char *path, ++ const char *unit, + bool show_properties, + bool *new_line, + bool *ellipsized) { + + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; ++ _cleanup_set_free_ Set *found_properties = NULL; ++ static const struct bus_properties_map property_map[] = { ++ { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) }, ++ { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) }, ++ {} ++ }; + UnitStatusInfo info = { + .memory_current = (uint64_t) -1, + .memory_limit = (uint64_t) -1, +@@ -4243,6 +4250,25 @@ static int show_one( + return r; + } + ++ if (unit) { ++ r = bus_message_map_all_properties(bus, reply, property_map, &info); ++ if (r < 0) ++ return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r)); ++ ++ if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) { ++ log_error("Unit %s could not be found.", unit); ++ ++ if (streq(verb, "status")) ++ return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; ++ ++ return -ENOENT; ++ } ++ ++ r = sd_bus_message_rewind(reply, true); ++ if (r < 0) ++ return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r)); ++ } ++ + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); + if (r < 0) + return bus_log_parse_error(r); +@@ -4267,9 +4293,17 @@ static int show_one( + if (r < 0) + return bus_log_parse_error(r); + +- if (show_properties) ++ if (show_properties) { ++ r = set_ensure_allocated(&found_properties, &string_hash_ops); ++ if (r < 0) ++ return log_oom(); ++ ++ r = set_put(found_properties, name); ++ if (r < 0 && r != EEXIST) ++ return log_oom(); ++ + r = print_property(name, reply, contents); +- else ++ } else + r = status_property(name, reply, &info, contents); + if (r < 0) + return r; +@@ -4291,35 +4325,30 @@ static int show_one( + + r = 0; + +- if (!show_properties) { +- if (streq(verb, "help")) +- show_unit_help(&info); ++ if (show_properties) { ++ char **pp; ++ ++ STRV_FOREACH(pp, arg_properties) { ++ if (!set_contains(found_properties, *pp)) { ++ log_warning("Property %s does not exist.", *pp); ++ r = -ENXIO; ++ } ++ } ++ } else if (streq(verb, "help")) ++ show_unit_help(&info); ++ else if (streq(verb, "status")) { ++ print_status_info(&info, ellipsized); ++ ++ if (info.active_state && STR_IN_SET(info.active_state, "inactive", "failed")) ++ r = EXIT_PROGRAM_NOT_RUNNING; + else +- print_status_info(&info, ellipsized); ++ r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK; + } + + strv_free(info.documentation); + strv_free(info.dropin_paths); + strv_free(info.listen); + +- if (!streq_ptr(info.active_state, "active") && +- !streq_ptr(info.active_state, "reloading") && +- streq(verb, "status")) { +- /* According to LSB: "program not running" */ +- /* 0: program is running or service is OK +- * 1: program is dead and /run PID file exists +- * 2: program is dead and /run/lock lock file exists +- * 3: program is not running +- * 4: program or service status is unknown +- */ +- if (info.pid_file && access(info.pid_file, F_OK) == 0) +- r = EXIT_PROGRAM_DEAD_AND_PID_EXISTS; +- else if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) +- r = EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN; +- else +- r = EXIT_PROGRAM_NOT_RUNNING; +- } +- + while ((p = info.exec)) { + LIST_REMOVE(exec, info.exec, p); + exec_status_info_free(p); +@@ -4394,7 +4423,7 @@ static int show_all( + if (!p) + return log_oom(); + +- r = show_one(verb, bus, p, show_properties, new_line, ellipsized); ++ r = show_one(verb, bus, p, u->id, show_properties, new_line, ellipsized); + if (r < 0) + return r; + else if (r > 0 && ret == 0) +@@ -4481,9 +4510,8 @@ static int show(sd_bus *bus, char **args) { + setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); + + /* If no argument is specified inspect the manager itself */ +- + if (show_properties && strv_length(args) <= 1) +- return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); ++ return show_one(args[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized); + + if (show_status && strv_length(args) <= 1) { + +@@ -4498,7 +4526,7 @@ static int show(sd_bus *bus, char **args) { + char **name; + + STRV_FOREACH(name, args + 1) { +- _cleanup_free_ char *unit = NULL; ++ _cleanup_free_ char *path = NULL, *unit = NULL; + uint32_t id; + + if (safe_atou32(*name, &id) < 0) { +@@ -4508,20 +4536,23 @@ static int show(sd_bus *bus, char **args) { + continue; + } else if (show_properties) { + /* Interpret as job id */ +- if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0) ++ if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0) + return log_oom(); + + } else { + /* Interpret as PID */ +- r = get_unit_dbus_path_by_pid(bus, id, &unit); ++ r = get_unit_dbus_path_by_pid(bus, id, &path); + if (r < 0) { + ret = r; + continue; + } ++ ++ r = unit_name_from_dbus_path(path, &unit); ++ if (r < 0) ++ return log_oom(); + } + +- r = show_one(args[0], bus, unit, show_properties, +- &new_line, &ellipsized); ++ r = show_one(args[0], bus, path, unit, show_properties, &new_line, &ellipsized); + if (r < 0) + return r; + else if (r > 0 && ret == 0) +@@ -4536,17 +4567,16 @@ static int show(sd_bus *bus, char **args) { + log_error_errno(r, "Failed to expand names: %m"); + + STRV_FOREACH(name, names) { +- _cleanup_free_ char *unit; ++ _cleanup_free_ char *path; + +- unit = unit_dbus_path_from_name(*name); +- if (!unit) ++ path = unit_dbus_path_from_name(*name); ++ if (!path) + return log_oom(); + +- r = show_one(args[0], bus, unit, show_properties, +- &new_line, &ellipsized); ++ r = show_one(args[0], bus, path, *name, show_properties, &new_line, &ellipsized); + if (r < 0) + return r; +- else if (r > 0 && ret == 0) ++ if (r > 0 && ret == 0) + ret = r; + } + } diff --git a/SOURCES/0344-journal-verify-don-t-hit-SIGFPE-when-determining-pro.patch b/SOURCES/0344-journal-verify-don-t-hit-SIGFPE-when-determining-pro.patch new file mode 100644 index 0000000..3bcc69f --- /dev/null +++ b/SOURCES/0344-journal-verify-don-t-hit-SIGFPE-when-determining-pro.patch @@ -0,0 +1,62 @@ +From 1466d84c159c1a9d1839c1b346906b722e6311a3 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 01:40:44 +0200 +Subject: [PATCH] journal-verify: don't hit SIGFPE when determining progress + +If we determine the progress based on a number of objects available, +don't blindly devide by the number of objects, given that it might be 0. + +Cherry-picked from: 45c047b227d96e98e7076c15ae774ff6390dc403 +Related: #1350232 +--- + src/journal/journal-verify.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index b03335e..983217c 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -69,6 +69,16 @@ static void draw_progress(uint64_t p, usec_t *last_usec) { + fflush(stdout); + } + ++static uint64_t scale_progress(uint64_t scale, uint64_t p, uint64_t m) { ++ ++ /* Calculates scale * p / m, but handles m == 0 safely, and saturates */ ++ ++ if (p >= m || m == 0) ++ return scale; ++ ++ return scale * p / m; ++} ++ + static void flush_progress(void) { + unsigned n, i; + +@@ -584,7 +594,7 @@ static int verify_hash_table( + uint64_t last = 0, p; + + if (show_progress) +- draw_progress(0xC000 + (0x3FFF * i / n), last_usec); ++ draw_progress(0xC000 + scale_progress(0x3FFF, i, n), last_usec); + + p = le64toh(f->data_hash_table[i].head_hash_offset); + while (p != 0) { +@@ -726,7 +736,7 @@ static int verify_entry_array( + Object *o; + + if (show_progress) +- draw_progress(0x8000 + (0x3FFF * i / n), last_usec); ++ draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec); + + if (a == 0) { + error(a, "array chain too short at %"PRIu64" of %"PRIu64, i, n); +@@ -863,7 +873,7 @@ int journal_file_verify( + p = le64toh(f->header->header_size); + while (p != 0) { + if (show_progress) +- draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec); ++ draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec); + + r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); + if (r < 0) { diff --git a/SOURCES/0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch b/SOURCES/0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch new file mode 100644 index 0000000..476804d --- /dev/null +++ b/SOURCES/0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch @@ -0,0 +1,162 @@ +From 283df68dbc1d90cad21beec6563215c26c69ec2c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 01:55:45 +0200 +Subject: [PATCH] journal: avoid mapping empty data and field hash tables + +When a new journal file is created we write the header first, then sync +and only then create the data and field hash tables in them. That means +to other processes it might appear that the files have a valid header +but not data and field hash tables. Our reader code should be able to +deal with this. + +With this change we'll not map the two hash tables right-away after +opening a file for reading anymore (because that will of course fail if +the objects are missing), but delay this until the first time we access +them. On top of that, when we want to look something up in the hash +tables and we notice they aren't initialized yet, we consider them +empty. + +This improves handling of some journal files reported in #487. + +Cherry-picked from: dade37d403f1b8c1d7bb2efbe2361f2a3e999613 +Related: #1350232 +--- + src/journal/journal-file.c | 37 ++++++++++++++++++++++++++----------- + src/journal/journal-file.h | 3 +++ + src/journal/journal-verify.c | 14 ++++++++++++++ + 3 files changed, 43 insertions(+), 11 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 892fe47..ef18497 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -656,13 +656,16 @@ static int journal_file_setup_field_hash_table(JournalFile *f) { + return 0; + } + +-static int journal_file_map_data_hash_table(JournalFile *f) { ++int journal_file_map_data_hash_table(JournalFile *f) { + uint64_t s, p; + void *t; + int r; + + assert(f); + ++ if (f->data_hash_table) ++ return 0; ++ + p = le64toh(f->header->data_hash_table_offset); + s = le64toh(f->header->data_hash_table_size); + +@@ -678,13 +681,16 @@ static int journal_file_map_data_hash_table(JournalFile *f) { + return 0; + } + +-static int journal_file_map_field_hash_table(JournalFile *f) { ++int journal_file_map_field_hash_table(JournalFile *f) { + uint64_t s, p; + void *t; + int r; + + assert(f); + ++ if (f->field_hash_table) ++ return 0; ++ + p = le64toh(f->header->field_hash_table_offset); + s = le64toh(f->header->field_hash_table_size); + +@@ -803,10 +809,18 @@ int journal_file_find_field_object_with_hash( + assert(f); + assert(field && size > 0); + ++ /* If the field hash table is empty, we can't find anything */ ++ if (le64toh(f->header->field_hash_table_size) <= 0) ++ return 0; ++ ++ /* Map the field hash table, if it isn't mapped yet. */ ++ r = journal_file_map_field_hash_table(f); ++ if (r < 0) ++ return r; ++ + osize = offsetof(Object, field.payload) + size; + + m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem); +- + if (m <= 0) + return -EBADMSG; + +@@ -866,6 +880,15 @@ int journal_file_find_data_object_with_hash( + assert(f); + assert(data || size == 0); + ++ /* If there's no data hash table, then there's no entry. */ ++ if (le64toh(f->header->data_hash_table_size) <= 0) ++ return 0; ++ ++ /* Map the data hash table, if it isn't mapped yet. */ ++ r = journal_file_map_data_hash_table(f); ++ if (r < 0) ++ return r; ++ + osize = offsetof(Object, data.payload) + size; + + m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); +@@ -2707,14 +2730,6 @@ int journal_file_open( + #endif + } + +- r = journal_file_map_field_hash_table(f); +- if (r < 0) +- goto fail; +- +- r = journal_file_map_data_hash_table(f); +- if (r < 0) +- goto fail; +- + if (mmap_cache_got_sigbus(f->mmap, f->fd)) { + r = -EIO; + goto fail; +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index 0f29b09..c74ad5f 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -234,3 +234,6 @@ static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) { + assert(f); + return f->compress_xz || f->compress_lz4; + } ++ ++int journal_file_map_data_hash_table(JournalFile *f); ++int journal_file_map_field_hash_table(JournalFile *f); +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index 983217c..d2d5c40 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -590,6 +590,13 @@ static int verify_hash_table( + assert(last_usec); + + n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); ++ if (n <= 0) ++ return 0; ++ ++ r = journal_file_map_data_hash_table(f); ++ if (r < 0) ++ return log_error_errno(r, "Failed to map data hash table: %m"); ++ + for (i = 0; i < n; i++) { + uint64_t last = 0, p; + +@@ -647,6 +654,13 @@ static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) + assert(f); + + n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); ++ if (n <= 0) ++ return 0; ++ ++ r = journal_file_map_data_hash_table(f); ++ if (r < 0) ++ return log_error_errno(r, "Failed to map data hash table: %m"); ++ + h = hash % n; + + q = le64toh(f->data_hash_table[h].head_hash_offset); diff --git a/SOURCES/0346-journal-when-verifying-journal-files-handle-empty-on.patch b/SOURCES/0346-journal-when-verifying-journal-files-handle-empty-on.patch new file mode 100644 index 0000000..96a659b --- /dev/null +++ b/SOURCES/0346-journal-when-verifying-journal-files-handle-empty-on.patch @@ -0,0 +1,84 @@ +From 0c2f52bb9b0bce392f14a38d6477e396d6fc987e Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 02:00:43 +0200 +Subject: [PATCH] journal: when verifying journal files, handle empty ones + nicely + +A journal file that carries no objects should be considered valid. + +Cherry-picked from: 8dc37a85255f68d62f7af66696cbf6a66401fb2a +Resolves: #1350232 +--- + src/journal/journal-verify.c | 37 ++++++++++++++----------------------- + 1 file changed, 14 insertions(+), 23 deletions(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index d2d5c40..53f0550 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -885,7 +885,11 @@ int journal_file_verify( + * superficial structure, headers, hashes. */ + + p = le64toh(f->header->header_size); +- while (p != 0) { ++ for (;;) { ++ /* Early exit if there are no objects in the file, at all */ ++ if (le64toh(f->header->tail_object_offset) == 0) ++ break; ++ + if (show_progress) + draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec); + +@@ -901,9 +905,6 @@ int journal_file_verify( + goto fail; + } + +- if (p == le64toh(f->header->tail_object_offset)) +- found_last = true; +- + n_objects ++; + + r = journal_file_object_verify(f, p, o); +@@ -1148,13 +1149,15 @@ int journal_file_verify( + n_weird ++; + } + +- if (p == le64toh(f->header->tail_object_offset)) +- p = 0; +- else +- p = p + ALIGN64(le64toh(o->object.size)); +- } ++ if (p == le64toh(f->header->tail_object_offset)) { ++ found_last = true; ++ break; ++ } + +- if (!found_last) { ++ p = p + ALIGN64(le64toh(o->object.size)); ++ }; ++ ++ if (!found_last && le64toh(f->header->tail_object_offset) != 0) { + error(le64toh(f->header->tail_object_offset), "tail object pointer dead"); + r = -EBADMSG; + goto fail; +@@ -1200,19 +1203,7 @@ int journal_file_verify( + goto fail; + } + +- if (n_data_hash_tables != 1) { +- error(0, "missing data hash table"); +- r = -EBADMSG; +- goto fail; +- } +- +- if (n_field_hash_tables != 1) { +- error(0, "missing field hash table"); +- r = -EBADMSG; +- goto fail; +- } +- +- if (!found_main_entry_array) { ++ if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) { + error(0, "missing entry array"); + r = -EBADMSG; + goto fail; diff --git a/SOURCES/0347-journal-explain-the-error-when-we-find-a-non-DATA-ob.patch b/SOURCES/0347-journal-explain-the-error-when-we-find-a-non-DATA-ob.patch new file mode 100644 index 0000000..3f0242f --- /dev/null +++ b/SOURCES/0347-journal-explain-the-error-when-we-find-a-non-DATA-ob.patch @@ -0,0 +1,31 @@ +From 8cfa250db93688a0796475cb911215e4edb252aa Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 02:02:07 +0200 +Subject: [PATCH] journal: explain the error when we find a non-DATA object + that is compressed + +Only objects of type DATA may be compressed, generate a message about +that, like we do for all other errros. + +Cherry-picked from: bca9e39dfadaefc4b02c0dd378adc3d6221071de +Related: #1350232 +--- + src/journal/journal-verify.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index 53f0550..77fb409 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -123,8 +123,10 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + * other objects. */ + + if ((o->object.flags & OBJECT_COMPRESSED_XZ) && +- o->object.type != OBJECT_DATA) ++ o->object.type != OBJECT_DATA) { ++ error(offset, "Found compressed object that isn't of type DATA, which is not allowed."); + return -EBADMSG; ++ } + + switch (o->object.type) { + diff --git a/SOURCES/0348-journalctl-properly-detect-empty-journal-files.patch b/SOURCES/0348-journalctl-properly-detect-empty-journal-files.patch new file mode 100644 index 0000000..c4d242c --- /dev/null +++ b/SOURCES/0348-journalctl-properly-detect-empty-journal-files.patch @@ -0,0 +1,31 @@ +From 8290b73eeb8da4f8f0076f3bb7e23990af734de0 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 02:10:32 +0200 +Subject: [PATCH] journalctl: properly detect empty journal files + +When we encounter a journal file with exactly zero entries, print a nice +message and exit, and don't print a weird error message. + +Cherry-picked from: 02ab86c732576a71179ce12e97d44c289833236d +Related: #1350232 +--- + src/journal/journalctl.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 6948ed6..904aae9 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -2141,6 +2141,12 @@ int main(int argc, char *argv[]) { + return EXIT_FAILURE; + } + ++ if (r == 0) { ++ printf("-- No entries --\n"); ++ return EXIT_SUCCESS; ++ } ++ ++ + if (!arg_follow) + pager_open_if_enabled(); + diff --git a/SOURCES/0349-journal-uppercase-first-character-in-verify-error-me.patch b/SOURCES/0349-journal-uppercase-first-character-in-verify-error-me.patch new file mode 100644 index 0000000..d679d33 --- /dev/null +++ b/SOURCES/0349-journal-uppercase-first-character-in-verify-error-me.patch @@ -0,0 +1,642 @@ +From 2a9dd5375b4f35a101d6ef3deb035d901d7a2392 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 24 Jul 2015 02:18:13 +0200 +Subject: [PATCH] journal: uppercase first character in verify error messages + +In the english language the first character of a sentence is supposed to +be uppercase. Let's make sure this also applies to the journal +verification error messages. + +Cherry-picked from: e80acc51aeaf2d74cb4d6cecbcb6e18f74c22c05 +Related: #1350232 +--- + src/journal/journal-verify.c | 162 ++++++++++++++++++++----------------------- + 1 file changed, 75 insertions(+), 87 deletions(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index 77fb409..8a66ac7 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -135,15 +135,15 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + int compression, r; + + if (le64toh(o->data.entry_offset) == 0) +- warning(offset, "unused data (entry_offset==0)"); ++ warning(offset, "Unused data (entry_offset==0)"); + + if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) { +- error(offset, "bad n_entries: %"PRIu64, o->data.n_entries); ++ error(offset, "Bad n_entries: %"PRIu64, o->data.n_entries); + return -EBADMSG; + } + + if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) { +- error(offset, "bad object size (<= %zu): %"PRIu64, ++ error(offset, "Bad object size (<= %zu): %"PRIu64, + offsetof(DataObject, payload), + le64toh(o->object.size)); + return -EBADMSG; +@@ -171,7 +171,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload)); + + if (h1 != h2) { +- error(offset, "invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2); ++ error(offset, "Invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2); + return -EBADMSG; + } + +@@ -179,7 +179,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + !VALID64(o->data.next_field_offset) || + !VALID64(o->data.entry_offset) || + !VALID64(o->data.entry_array_offset)) { +- error(offset, "invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt, ++ error(offset, "Invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt, + o->data.next_hash_offset, + o->data.next_field_offset, + o->data.entry_offset, +@@ -193,7 +193,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + case OBJECT_FIELD: + if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) { + error(offset, +- "bad field size (<= %zu): %"PRIu64, ++ "Bad field size (<= %zu): %"PRIu64, + offsetof(FieldObject, payload), + le64toh(o->object.size)); + return -EBADMSG; +@@ -202,7 +202,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (!VALID64(o->field.next_hash_offset) || + !VALID64(o->field.head_data_offset)) { + error(offset, +- "invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt, ++ "Invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt, + o->field.next_hash_offset, + o->field.head_data_offset); + return -EBADMSG; +@@ -212,7 +212,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + case OBJECT_ENTRY: + if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) { + error(offset, +- "bad entry size (<= %zu): %"PRIu64, ++ "Bad entry size (<= %zu): %"PRIu64, + offsetof(EntryObject, items), + le64toh(o->object.size)); + return -EBADMSG; +@@ -220,28 +220,28 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + + if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) { + error(offset, +- "invalid number items in entry: %"PRIu64, ++ "Invalid number items in entry: %"PRIu64, + (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem)); + return -EBADMSG; + } + + if (le64toh(o->entry.seqnum) <= 0) { + error(offset, +- "invalid entry seqnum: %"PRIx64, ++ "Invalid entry seqnum: %"PRIx64, + le64toh(o->entry.seqnum)); + return -EBADMSG; + } + + if (!VALID_REALTIME(le64toh(o->entry.realtime))) { + error(offset, +- "invalid entry realtime timestamp: %"PRIu64, ++ "Invalid entry realtime timestamp: %"PRIu64, + le64toh(o->entry.realtime)); + return -EBADMSG; + } + + if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) { + error(offset, +- "invalid entry monotonic timestamp: %"PRIu64, ++ "Invalid entry monotonic timestamp: %"PRIu64, + le64toh(o->entry.monotonic)); + return -EBADMSG; + } +@@ -250,7 +250,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (o->entry.items[i].object_offset == 0 || + !VALID64(o->entry.items[i].object_offset)) { + error(offset, +- "invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt, ++ "Invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt, + i, journal_file_entry_n_items(o), + o->entry.items[i].object_offset); + return -EBADMSG; +@@ -264,7 +264,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 || + (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) { + error(offset, +- "invalid %s hash table size: %"PRIu64, ++ "Invalid %s hash table size: %"PRIu64, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + le64toh(o->object.size)); + return -EBADMSG; +@@ -274,7 +274,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (o->hash_table.items[i].head_hash_offset != 0 && + !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) { + error(offset, +- "invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt, ++ "Invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].head_hash_offset)); +@@ -283,7 +283,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (o->hash_table.items[i].tail_hash_offset != 0 && + !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) { + error(offset, +- "invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt, ++ "Invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].tail_hash_offset)); +@@ -293,7 +293,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if ((o->hash_table.items[i].head_hash_offset != 0) != + (o->hash_table.items[i].tail_hash_offset != 0)) { + error(offset, +- "invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt, ++ "Invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt, + o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", + i, journal_file_hash_table_n_items(o), + le64toh(o->hash_table.items[i].head_hash_offset), +@@ -308,14 +308,14 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 || + (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) { + error(offset, +- "invalid object entry array size: %"PRIu64, ++ "Invalid object entry array size: %"PRIu64, + le64toh(o->object.size)); + return -EBADMSG; + } + + if (!VALID64(o->entry_array.next_entry_array_offset)) { + error(offset, +- "invalid object entry array next_entry_array_offset: "OFSfmt, ++ "Invalid object entry array next_entry_array_offset: "OFSfmt, + o->entry_array.next_entry_array_offset); + return -EBADMSG; + } +@@ -324,7 +324,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + if (le64toh(o->entry_array.items[i]) != 0 && + !VALID64(le64toh(o->entry_array.items[i]))) { + error(offset, +- "invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt, ++ "Invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt, + i, journal_file_entry_array_n_items(o), + le64toh(o->entry_array.items[i])); + return -EBADMSG; +@@ -335,14 +335,14 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o + case OBJECT_TAG: + if (le64toh(o->object.size) != sizeof(TagObject)) { + error(offset, +- "invalid object tag size: %"PRIu64, ++ "Invalid object tag size: %"PRIu64, + le64toh(o->object.size)); + return -EBADMSG; + } + + if (!VALID_EPOCH(o->tag.epoch)) { + error(offset, +- "invalid object tag epoch: %"PRIu64, ++ "Invalid object tag epoch: %"PRIu64, + o->tag.epoch); + return -EBADMSG; + } +@@ -415,8 +415,7 @@ static int entry_points_to_data( + assert(entry_fd >= 0); + + if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) { +- error(data_p, +- "data object references invalid entry at "OFSfmt, entry_p); ++ error(data_p, "Data object references invalid entry at "OFSfmt, entry_p); + return -EBADMSG; + } + +@@ -432,8 +431,7 @@ static int entry_points_to_data( + } + + if (!found) { +- error(entry_p, +- "data object at "OFSfmt" not referenced by linked entry", data_p); ++ error(entry_p, "Data object at "OFSfmt" not referenced by linked entry", data_p); + return -EBADMSG; + } + +@@ -476,7 +474,7 @@ static int entry_points_to_data( + x = z; + } + +- error(entry_p, "entry object doesn't exist in main entry array"); ++ error(entry_p, "Entry object doesn't exist in main entry array"); + return -EBADMSG; + } + +@@ -506,9 +504,7 @@ static int verify_data( + + /* Entry array means at least two objects */ + if (a && n < 2) { +- error(p, +- "entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", +- a, n); ++ error(p, "Entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", a, n); + return -EBADMSG; + } + +@@ -528,12 +524,12 @@ static int verify_data( + uint64_t next, m, j; + + if (a == 0) { +- error(p, "array chain too short"); ++ error(p, "Array chain too short"); + return -EBADMSG; + } + + if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) { +- error(p, "invalid array offset "OFSfmt, a); ++ error(p, "Invalid array offset "OFSfmt, a); + return -EBADMSG; + } + +@@ -543,8 +539,7 @@ static int verify_data( + + next = le64toh(o->entry_array.next_entry_array_offset); + if (next != 0 && next <= a) { +- error(p, "array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", +- a, next); ++ error(p, "Array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", a, next); + return -EBADMSG; + } + +@@ -553,7 +548,7 @@ static int verify_data( + + q = le64toh(o->entry_array.items[j]); + if (q <= last) { +- error(p, "data object's entry array not sorted"); ++ error(p, "Data object's entry array not sorted"); + return -EBADMSG; + } + last = q; +@@ -611,8 +606,7 @@ static int verify_hash_table( + uint64_t next; + + if (!contains_uint64(f->mmap, data_fd, n_data, p)) { +- error(p, "invalid data object at hash entry %"PRIu64" of %"PRIu64, +- i, n); ++ error(p, "Invalid data object at hash entry %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + +@@ -622,14 +616,12 @@ static int verify_hash_table( + + next = le64toh(o->data.next_hash_offset); + if (next != 0 && next <= p) { +- error(p, "hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, +- i, n); ++ error(p, "Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + + if (le64toh(o->data.hash) % n != i) { +- error(p, "hash value mismatch in hash entry %"PRIu64" of %"PRIu64, +- i, n); ++ error(p, "Hash value mismatch in hash entry %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + +@@ -642,7 +634,7 @@ static int verify_hash_table( + } + + if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) { +- error(p, "tail hash pointer mismatch in hash table"); ++ error(p, "Tail hash pointer mismatch in hash table"); + return -EBADMSG; + } + } +@@ -703,16 +695,16 @@ static int verify_entry( + h = le64toh(o->entry.items[i].hash); + + if (!contains_uint64(f->mmap, data_fd, n_data, q)) { +- error(p, "invalid data object of entry"); +- return -EBADMSG; +- } ++ error(p, "Invalid data object of entry"); ++ return -EBADMSG; ++ } + + r = journal_file_move_to_object(f, OBJECT_DATA, q, &u); + if (r < 0) + return r; + + if (le64toh(u->data.hash) != h) { +- error(p, "hash mismatch for data object of entry"); ++ error(p, "Hash mismatch for data object of entry"); + return -EBADMSG; + } + +@@ -720,7 +712,7 @@ static int verify_entry( + if (r < 0) + return r; + if (r == 0) { +- error(p, "data object missing from hash table"); ++ error(p, "Data object missing from hash table"); + return -EBADMSG; + } + } +@@ -755,12 +747,12 @@ static int verify_entry_array( + draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec); + + if (a == 0) { +- error(a, "array chain too short at %"PRIu64" of %"PRIu64, i, n); ++ error(a, "Array chain too short at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + + if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) { +- error(a, "invalid array %"PRIu64" of %"PRIu64, i, n); ++ error(a, "Invalid array %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + +@@ -770,9 +762,7 @@ static int verify_entry_array( + + next = le64toh(o->entry_array.next_entry_array_offset); + if (next != 0 && next <= a) { +- error(a, +- "array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", +- i, n, next); ++ error(a, "Array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", i, n, next); + return -EBADMSG; + } + +@@ -782,15 +772,13 @@ static int verify_entry_array( + + p = le64toh(o->entry_array.items[j]); + if (p <= last) { +- error(a, "entry array not sorted at %"PRIu64" of %"PRIu64, +- i, n); ++ error(a, "Entry array not sorted at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + last = p; + + if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) { +- error(a, "invalid array entry at %"PRIu64" of %"PRIu64, +- i, n); ++ error(a, "Invalid array entry at %"PRIu64" of %"PRIu64, i, n); + return -EBADMSG; + } + +@@ -878,7 +866,7 @@ int journal_file_verify( + + for (i = 0; i < sizeof(f->header->reserved); i++) + if (f->header->reserved[i] != 0) { +- error(offsetof(Header, reserved[i]), "reserved field is non-zero"); ++ error(offsetof(Header, reserved[i]), "Reserved field is non-zero"); + r = -EBADMSG; + goto fail; + } +@@ -897,12 +885,12 @@ int journal_file_verify( + + r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); + if (r < 0) { +- error(p, "invalid object"); ++ error(p, "Invalid object"); + goto fail; + } + + if (p > le64toh(f->header->tail_object_offset)) { +- error(offsetof(Header, tail_object_offset), "invalid tail object pointer"); ++ error(offsetof(Header, tail_object_offset), "Invalid tail object pointer"); + r = -EBADMSG; + goto fail; + } +@@ -911,13 +899,13 @@ int journal_file_verify( + + r = journal_file_object_verify(f, p, o); + if (r < 0) { +- error(p, "invalid object contents: %s", strerror(-r)); ++ error(p, "Envalid object contents: %s", strerror(-r)); + goto fail; + } + + if ((o->object.flags & OBJECT_COMPRESSED_XZ) && + (o->object.flags & OBJECT_COMPRESSED_LZ4)) { +- error(p, "objected with double compression"); ++ error(p, "Objected with double compression"); + r = -EINVAL; + goto fail; + } +@@ -950,7 +938,7 @@ int journal_file_verify( + + case OBJECT_ENTRY: + if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) { +- error(p, "first entry before first tag"); ++ error(p, "First entry before first tag"); + r = -EBADMSG; + goto fail; + } +@@ -960,21 +948,21 @@ int journal_file_verify( + goto fail; + + if (le64toh(o->entry.realtime) < last_tag_realtime) { +- error(p, "older entry after newer tag"); ++ error(p, "Older entry after newer tag"); + r = -EBADMSG; + goto fail; + } + + if (!entry_seqnum_set && + le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) { +- error(p, "head entry sequence number incorrect"); ++ error(p, "Head entry sequence number incorrect"); + r = -EBADMSG; + goto fail; + } + + if (entry_seqnum_set && + entry_seqnum >= le64toh(o->entry.seqnum)) { +- error(p, "entry sequence number out of synchronization"); ++ error(p, "Entry sequence number out of synchronization"); + r = -EBADMSG; + goto fail; + } +@@ -985,7 +973,7 @@ int journal_file_verify( + if (entry_monotonic_set && + sd_id128_equal(entry_boot_id, o->entry.boot_id) && + entry_monotonic > le64toh(o->entry.monotonic)) { +- error(p, "entry timestamp out of synchronization"); ++ error(p, "Entry timestamp out of synchronization"); + r = -EBADMSG; + goto fail; + } +@@ -996,7 +984,7 @@ int journal_file_verify( + + if (!entry_realtime_set && + le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) { +- error(p, "head entry realtime timestamp incorrect"); ++ error(p, "Head entry realtime timestamp incorrect"); + r = -EBADMSG; + goto fail; + } +@@ -1009,7 +997,7 @@ int journal_file_verify( + + case OBJECT_DATA_HASH_TABLE: + if (n_data_hash_tables > 1) { +- error(p, "more than one data hash table"); ++ error(p, "More than one data hash table"); + r = -EBADMSG; + goto fail; + } +@@ -1026,14 +1014,14 @@ int journal_file_verify( + + case OBJECT_FIELD_HASH_TABLE: + if (n_field_hash_tables > 1) { +- error(p, "more than one field hash table"); ++ error(p, "More than one field hash table"); + r = -EBADMSG; + goto fail; + } + + if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) || + le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) { +- error(p, "header fields for field hash table invalid"); ++ error(p, "Header fields for field hash table invalid"); + r = -EBADMSG; + goto fail; + } +@@ -1048,7 +1036,7 @@ int journal_file_verify( + + if (p == le64toh(f->header->entry_array_offset)) { + if (found_main_entry_array) { +- error(p, "more than one main entry array"); ++ error(p, "More than one main entry array"); + r = -EBADMSG; + goto fail; + } +@@ -1061,19 +1049,19 @@ int journal_file_verify( + + case OBJECT_TAG: + if (!JOURNAL_HEADER_SEALED(f->header)) { +- error(p, "tag object in file without sealing"); ++ error(p, "Tag object in file without sealing"); + r = -EBADMSG; + goto fail; + } + + if (le64toh(o->tag.seqnum) != n_tags + 1) { +- error(p, "tag sequence number out of synchronization"); ++ error(p, "Tag sequence number out of synchronization"); + r = -EBADMSG; + goto fail; + } + + if (le64toh(o->tag.epoch) < last_epoch) { +- error(p, "epoch sequence out of synchronization"); ++ error(p, "Epoch sequence out of synchronization"); + r = -EBADMSG; + goto fail; + } +@@ -1082,7 +1070,7 @@ int journal_file_verify( + if (f->seal) { + uint64_t q, rt; + +- debug(p, "checking tag %"PRIu64"...", le64toh(o->tag.seqnum)); ++ debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum)); + + rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec; + if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) { +@@ -1129,7 +1117,7 @@ int journal_file_verify( + goto fail; + + if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) { +- error(p, "tag failed verification"); ++ error(p, "Tag failed verification"); + r = -EBADMSG; + goto fail; + } +@@ -1160,60 +1148,60 @@ int journal_file_verify( + }; + + if (!found_last && le64toh(f->header->tail_object_offset) != 0) { +- error(le64toh(f->header->tail_object_offset), "tail object pointer dead"); ++ error(le64toh(f->header->tail_object_offset), "Tail object pointer dead"); + r = -EBADMSG; + goto fail; + } + + if (n_objects != le64toh(f->header->n_objects)) { +- error(offsetof(Header, n_objects), "object number mismatch"); ++ error(offsetof(Header, n_objects), "Object number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (n_entries != le64toh(f->header->n_entries)) { +- error(offsetof(Header, n_entries), "entry number mismatch"); ++ error(offsetof(Header, n_entries), "Entry number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_data) && + n_data != le64toh(f->header->n_data)) { +- error(offsetof(Header, n_data), "data number mismatch"); ++ error(offsetof(Header, n_data), "Data number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) && + n_fields != le64toh(f->header->n_fields)) { +- error(offsetof(Header, n_fields), "field number mismatch"); ++ error(offsetof(Header, n_fields), "Field number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) && + n_tags != le64toh(f->header->n_tags)) { +- error(offsetof(Header, n_tags), "tag number mismatch"); ++ error(offsetof(Header, n_tags), "Tag number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) && + n_entry_arrays != le64toh(f->header->n_entry_arrays)) { +- error(offsetof(Header, n_entry_arrays), "entry array number mismatch"); ++ error(offsetof(Header, n_entry_arrays), "Entry array number mismatch"); + r = -EBADMSG; + goto fail; + } + + if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) { +- error(0, "missing entry array"); ++ error(0, "Missing entry array"); + r = -EBADMSG; + goto fail; + } + + if (entry_seqnum_set && + entry_seqnum != le64toh(f->header->tail_entry_seqnum)) { +- error(offsetof(Header, tail_entry_seqnum), "invalid tail seqnum"); ++ error(offsetof(Header, tail_entry_seqnum), "Invalid tail seqnum"); + r = -EBADMSG; + goto fail; + } +@@ -1221,13 +1209,13 @@ int journal_file_verify( + if (entry_monotonic_set && + (!sd_id128_equal(entry_boot_id, f->header->boot_id) || + entry_monotonic != le64toh(f->header->tail_entry_monotonic))) { +- error(0, "invalid tail monotonic timestamp"); ++ error(0, "Invalid tail monotonic timestamp"); + r = -EBADMSG; + goto fail; + } + + if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) { +- error(0, "invalid tail realtime timestamp"); ++ error(0, "Invalid tail realtime timestamp"); + r = -EBADMSG; + goto fail; + } diff --git a/SOURCES/0350-journalctl-make-sure-journalctl-f-t-unmatched-blocks.patch b/SOURCES/0350-journalctl-make-sure-journalctl-f-t-unmatched-blocks.patch new file mode 100644 index 0000000..7de0a54 --- /dev/null +++ b/SOURCES/0350-journalctl-make-sure-journalctl-f-t-unmatched-blocks.patch @@ -0,0 +1,48 @@ +From 3045db86f9185f6de78f85099159330dfc1a0e9e Mon Sep 17 00:00:00 2001 +From: Stef Walter +Date: Fri, 14 Aug 2015 16:38:41 +0200 +Subject: [PATCH] journalctl: make sure 'journalctl -f -t unmatched' blocks + +Previously the following command: + +$ journalctl -f -t unmatchedtag12345 + +... would block when called with criteria that did not match any +journal lines. Once log lines appeared that matched the criteria +they were displayed. + +Commit 02ab86c732576a71179ce12e97d44c289833236d broke this +behavior and the journal was not followed, but the command +exits with '-- No entries --' displayed. + +This commit fixes the issue. + +More information downstream: + +https://bugzilla.redhat.com/show_bug.cgi?id=1253649 + +Cherry-picked from: c51e1a96359b3f4d374345593b11273df2132b93 +Related: #1350232 +--- + src/journal/journalctl.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 904aae9..2688d8b 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -2142,8 +2142,12 @@ int main(int argc, char *argv[]) { + } + + if (r == 0) { +- printf("-- No entries --\n"); +- return EXIT_SUCCESS; ++ if (arg_follow) ++ need_seek = true; ++ else { ++ printf("-- No entries --\n"); ++ return EXIT_SUCCESS; ++ } + } + + diff --git a/SOURCES/0351-journalctl-don-t-print-No-entries-in-quiet-mode.patch b/SOURCES/0351-journalctl-don-t-print-No-entries-in-quiet-mode.patch new file mode 100644 index 0000000..2478c48 --- /dev/null +++ b/SOURCES/0351-journalctl-don-t-print-No-entries-in-quiet-mode.patch @@ -0,0 +1,25 @@ +From 13f24902c7c1ba91d41bf4e8dd694cf01f876938 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Tue, 17 Nov 2015 06:06:52 +0000 +Subject: [PATCH] journalctl: don't print -- No entries -- in quiet mode + +Cherry-picked from: bfcb7c5f5333f9c3523b7027c2ad4c99e4494fb5 +Related: #1350232 +--- + src/journal/journalctl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 2688d8b..a38ce4b 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -2145,7 +2145,8 @@ int main(int argc, char *argv[]) { + if (arg_follow) + need_seek = true; + else { +- printf("-- No entries --\n"); ++ if (!arg_quiet) ++ printf("-- No entries --\n"); + return EXIT_SUCCESS; + } + } diff --git a/SOURCES/0352-sd-event-expose-the-event-loop-iteration-counter-via.patch b/SOURCES/0352-sd-event-expose-the-event-loop-iteration-counter-via.patch new file mode 100644 index 0000000..79865b4 --- /dev/null +++ b/SOURCES/0352-sd-event-expose-the-event-loop-iteration-counter-via.patch @@ -0,0 +1,69 @@ +From 8fe5d9138039aafd314340b12d6d586d657d53a7 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 29 Jun 2016 19:03:26 -0700 +Subject: [PATCH] sd-event: expose the event loop iteration counter via + sd_event_get_iteration() + +This extends the existing event loop iteration counter to 64bit, and exposes it +via a new function sd_event_get_iteration(). This is helpful for cases like +issue #3612. After all, since we maintain the counter anyway, we might as well +expose it. + +(This also fixes an unrelated issue in the man page for sd_event_wait() where +micro and milliseconds got mixed up) + +Cherry-picked from: 7486322b99da5b4d2d00d35b310b035f936f7964 +Related: #1342173 +--- + src/libsystemd/sd-event/sd-event.c | 14 +++++++++++--- + src/systemd/sd-event.h | 1 + + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index 1f1e6fe..9d48e5a 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -76,8 +76,8 @@ struct sd_event_source { + int64_t priority; + unsigned pending_index; + unsigned prepare_index; +- unsigned pending_iteration; +- unsigned prepare_iteration; ++ uint64_t pending_iteration; ++ uint64_t prepare_iteration; + + LIST_FIELDS(sd_event_source, sources); + +@@ -169,7 +169,7 @@ struct sd_event { + + pid_t original_pid; + +- unsigned iteration; ++ uint64_t iteration; + dual_timestamp timestamp; + usec_t timestamp_boottime; + int state; +@@ -2689,3 +2689,11 @@ _public_ int sd_event_get_watchdog(sd_event *e) { + + return e->watchdog; + } ++ ++_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { ++ assert_return(e, -EINVAL); ++ assert_return(!event_pid_changed(e), -ECHILD); ++ ++ *ret = e->iteration; ++ return 0; ++} +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index 25a10f9..4957f3a 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -101,6 +101,7 @@ int sd_event_get_tid(sd_event *e, pid_t *tid); + int sd_event_get_exit_code(sd_event *e, int *code); + int sd_event_set_watchdog(sd_event *e, int b); + int sd_event_get_watchdog(sd_event *e); ++int sd_event_get_iteration(sd_event *e, uint64_t *ret); + + sd_event_source* sd_event_source_ref(sd_event_source *s); + sd_event_source* sd_event_source_unref(sd_event_source *s); diff --git a/SOURCES/0353-manager-Only-invoke-a-single-sigchld-per-unit-within.patch b/SOURCES/0353-manager-Only-invoke-a-single-sigchld-per-unit-within.patch new file mode 100644 index 0000000..962c65f --- /dev/null +++ b/SOURCES/0353-manager-Only-invoke-a-single-sigchld-per-unit-within.patch @@ -0,0 +1,85 @@ +From 2a0feeb4252cbf1207f45e978fe7eb02bb0182ec Mon Sep 17 00:00:00 2001 +From: Kyle Walker +Date: Thu, 30 Jun 2016 15:12:18 -0400 +Subject: [PATCH] manager: Only invoke a single sigchld per unit within a + cleanup cycle + +By default, each iteration of manager_dispatch_sigchld() results in a unit level +sigchld event being invoked. For scope units, this results in a scope_sigchld_event() +which can seemingly stall for workloads that have a large number of PIDs within the +scope. The stall exhibits itself as a SIG_0 being initiated for each u->pids entry +as a result of pid_is_unwaited(). + +v2: +This patch resolves this condition by only paying to cost of a sigchld in the underlying +scope unit once per sigchld iteration. A new "sigchldgen" member resides within the +Unit struct. The Manager is incremented via the sd event loop, accessed via +sd_event_get_iteration, and the Unit member is set to the same value as the manager each +time that a sigchld event is invoked. If the Manager iteration value and Unit member +match, the sigchld event is not invoked for that iteration. + +Cherry-picked from: 36f20ae3b2975e44b6ef17e453ae06a289e9a122 +Resolves: #1342173 +--- + src/core/manager.c | 13 ++++++++++++- + src/core/unit.c | 1 + + src/core/unit.h | 3 +++ + 3 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index e5226a8..63693b9 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1747,14 +1747,25 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + } + + static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { ++ uint64_t iteration; ++ + assert(m); + assert(u); + assert(si); + ++ sd_event_get_iteration(m->event, &iteration); ++ + log_unit_debug(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id); + + unit_unwatch_pid(u, si->si_pid); +- UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); ++ ++ if (UNIT_VTABLE(u)->sigchld_event) { ++ if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { ++ UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); ++ u->sigchldgen = iteration; ++ } else ++ log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); ++ } + } + + static int manager_dispatch_sigchld(Manager *m) { +diff --git a/src/core/unit.c b/src/core/unit.c +index d6ead7d..d62135d 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -94,6 +94,7 @@ Unit *unit_new(Manager *m, size_t size) { + u->unit_file_state = _UNIT_FILE_STATE_INVALID; + u->unit_file_preset = -1; + u->on_failure_job_mode = JOB_REPLACE; ++ u->sigchldgen = 0; + + return u; + } +diff --git a/src/core/unit.h b/src/core/unit.h +index 0eebc0b..d936457 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -167,6 +167,9 @@ struct Unit { + * process SIGCHLD for */ + Set *pids; + ++ /* Used in sigchld event invocation to avoid repeat events being invoked */ ++ uint64_t sigchldgen; ++ + /* Used during GC sweeps */ + unsigned gc_marker; + diff --git a/SOURCES/0354-manager-Fixing-a-debug-printf-formatting-mistake.patch b/SOURCES/0354-manager-Fixing-a-debug-printf-formatting-mistake.patch new file mode 100644 index 0000000..7d91382 --- /dev/null +++ b/SOURCES/0354-manager-Fixing-a-debug-printf-formatting-mistake.patch @@ -0,0 +1,28 @@ +From 1a6aae42bb3c4e524ded2da53afa303dd479b877 Mon Sep 17 00:00:00 2001 +From: Kyle Walker +Date: Fri, 1 Jul 2016 10:04:40 -0400 +Subject: [PATCH] manager: Fixing a debug printf formatting mistake + +A 'llu' formatting statement was used in a debugging printf statement +instead of a 'PRIu64'. Correcting that mistake here. + +Cherry-picked from: 72b0c3f59695239c51b719576f625e789bd00a66 +Related: #1342173 +--- + src/core/manager.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 63693b9..d168777 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1764,7 +1764,8 @@ static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); + u->sigchldgen = iteration; + } else +- log_debug("%s already issued a sigchld this iteration %llu, skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); ++ log_debug("%s already issued a sigchld this iteration %" PRIu64 ", skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids)); ++ + } + } + diff --git a/SOURCES/0355-core-support-IEC-suffixes-for-RLIMIT-stuff.patch b/SOURCES/0355-core-support-IEC-suffixes-for-RLIMIT-stuff.patch new file mode 100644 index 0000000..7791eba --- /dev/null +++ b/SOURCES/0355-core-support-IEC-suffixes-for-RLIMIT-stuff.patch @@ -0,0 +1,191 @@ +From 99074eebc911728a41167c1962231e11b5e3cddd Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 6 Nov 2015 11:06:52 +0100 +Subject: [PATCH] core: support IEC suffixes for RLIMIT stuff + +Let's make things more user-friendly and support for example + + LimitAS=16G + +rather than force users to always use LimitAS=16106127360. + +The change is relevant for options: + + [Default]Limit{FSIZE,DATA,STACK,CORE,RSS,AS,MEMLOCK,MSGQUEUE} + +The patch introduces config_parse_bytes_limit(), it's the same as +config_parse_limit() but uses parse_size() tu support the suffixes. + +Addresses: https://github.com/systemd/systemd/issues/1772 + +Cherry-picked from: 412ea7a936ebaa5342a4c2abf48b9e408e6ba5dc +Related: #1351415 +--- + man/systemd-system.conf.xml | 6 +++-- + man/systemd.exec.xml | 4 +++- + src/core/load-fragment-gperf.gperf.m4 | 16 ++++++------- + src/core/load-fragment.c | 43 +++++++++++++++++++++++++++++++++++ + src/core/load-fragment.h | 1 + + src/core/main.c | 16 ++++++------- + 6 files changed, 67 insertions(+), 19 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index ca25c93..b7d9cde 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -327,8 +327,10 @@ + resource limits for units. See + setrlimit2 + for details. Use the string infinity to +- configure no limit on a specific resource. These settings may +- be overridden in individual units using the corresponding ++ configure no limit on a specific resource. The multiplicative suffixes ++ K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for ++ resource limits measured in bytes (e.g. DefaultLimitAS=16G). These ++ settings may be overridden in individual units using the corresponding + LimitXXX= directives. Note that these resource limits are only + defaults for units, they are not applied to PID 1 + itself. +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 6af7c7a..25aea16 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -559,7 +559,9 @@ + of various resources for executed processes. See + setrlimit2 + for details. Use the string infinity to +- configure no limit on a specific resource. ++ configure no limit on a specific resource. The multiplicative suffixes ++ K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for ++ resource limits measured in bytes (e.g. LimitAS=16G). + + + Limit directives and their equivalent with ulimit +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index 85d9797..c3461a0 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -59,18 +59,18 @@ $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CO + $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 + $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') + $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) +-$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) +-$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) +-$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +-$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) +-$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) ++$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) ++$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) ++$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) ++$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) ++$1.LimitRSS, config_parse_bytes_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) + $1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) +-$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) ++$1.LimitAS, config_parse_bytes_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) + $1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) +-$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) ++$1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) + $1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) + $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) +-$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) ++$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) + $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) + $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) + $1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index b188ec9..dbb45b2 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1119,6 +1119,49 @@ int config_parse_limit(const char *unit, + return 0; + } + ++int config_parse_bytes_limit(const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ ++ struct rlimit **rl = data; ++ uint64_t bytes; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ rl += ltype; ++ ++ if (streq(rvalue, "infinity")) ++ bytes = (uint64_t) RLIM_INFINITY; ++ else { ++ int r; ++ ++ r = parse_size(rvalue, 1024, &bytes); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); ++ return 0; ++ } ++ } ++ ++ if (!*rl) { ++ *rl = new(struct rlimit, 1); ++ if (!*rl) ++ return log_oom(); ++ } ++ ++ (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) bytes; ++ return 0; ++} ++ + #ifdef HAVE_SYSV_COMPAT + int config_parse_sysv_priority(const char *unit, + const char *filename, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index ce10d03..2d509d0 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -56,6 +56,7 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig + int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/core/main.c b/src/core/main.c +index 2aec40b..60ea36c 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -655,18 +655,18 @@ static int parse_config_file(void) { + { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, + { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, + { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] }, +- { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, +- { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, +- { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, +- { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, +- { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, ++ { "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, ++ { "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, ++ { "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, ++ { "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, ++ { "Manager", "DefaultLimitRSS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, + { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] }, +- { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, ++ { "Manager", "DefaultLimitAS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, + { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] }, +- { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, ++ { "Manager", "DefaultLimitMEMLOCK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, + { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] }, + { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] }, +- { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, ++ { "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, + { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] }, + { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] }, + { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, diff --git a/SOURCES/0356-core-accept-time-units-for-time-based-resource-limit.patch b/SOURCES/0356-core-accept-time-units-for-time-based-resource-limit.patch new file mode 100644 index 0000000..a0ce023 --- /dev/null +++ b/SOURCES/0356-core-accept-time-units-for-time-based-resource-limit.patch @@ -0,0 +1,416 @@ +From 128ef85392f68fa32650deab12d6cd2e01ad52cf Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 10 Nov 2015 16:52:52 +0100 +Subject: [PATCH] core: accept time units for time-based resource limits + +Let's make sure "LimitCPU=30min" can be parsed properly, following the +usual logic how we parse time values. Similar for LimitRTTIME=. + +While we are at it, extend a bit on the man page section about resource +limits. + +Fixes: #1772 + +Cherry-picked from: a4c1800284e3546bbfab2dc19eb59bcb91c4a2ca +Related: #1351415 +--- + man/systemd.exec.xml | 86 ++++++++++++++++++++++------- + src/core/load-fragment-gperf.gperf.m4 | 4 +- + src/core/load-fragment.c | 101 ++++++++++++++++++++++++++++++++++ + src/core/load-fragment.h | 2 + + src/test/test-unit-file.c | 61 ++++++++++++++++++++ + 5 files changed, 231 insertions(+), 23 deletions(-) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 25aea16..cfdcc3d 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -559,90 +559,133 @@ + of various resources for executed processes. See + setrlimit2 + for details. Use the string infinity to +- configure no limit on a specific resource. The multiplicative suffixes +- K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for +- resource limits measured in bytes (e.g. LimitAS=16G). ++ configure no limit on a specific resource. The multiplicative ++ suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E ++ may be used for resource limits measured in bytes ++ (e.g. LimitAS=16G). For the limits referring to time values, ++ the usual time units ms, s, min, h and so on may be used (see ++ systemd.time7 ++ for details). Note that if no time unit is specified for ++ LimitCPU= the default unit of seconds is ++ implied, while for LimitRTTIME= the default ++ unit of microseconds is implied. Also, note that the effective ++ granularity of the limits might influence their ++ enforcement. For example, time limits specified for ++ LimitCPU= will be rounded up implicitly to ++ multiples of 1s. ++ ++ Note that most process resource limits configured with ++ these options are per-process, and processes may fork in order ++ to acquire a new set of resources that are accounted ++ independently of the original process, and may thus escape ++ limits set. Also note that LimitRSS= is not ++ implemented on Linux, and setting it has no effect. Often it ++ is advisable to prefer the resource controls listed in ++ systemd.resource-control5 ++ over these per-process limits, as they apply to services as a ++ whole, may be altered dynamically at runtime, and are ++ generally more expressive. For example, ++ MemoryLimit= is a more powerful (and ++ working) replacement for LimitRSS=. + +
+ Limit directives and their equivalent with ulimit + +- ++ + + ++ + + + Directive + ulimit equivalent ++ Unit + + + + +- LimitCPU ++ LimitCPU= + ulimit -t ++ Seconds + + +- LimitFSIZE ++ LimitFSIZE= + ulimit -f ++ Bytes + + +- LimitDATA ++ LimitDATA= + ulimit -d ++ Bytes + + +- LimitSTACK ++ LimitSTACK= + ulimit -s ++ Bytes + + +- LimitCORE ++ LimitCORE= + ulimit -c ++ Bytes + + +- LimitRSS ++ LimitRSS= + ulimit -m ++ Bytes + + +- LimitNOFILE ++ LimitNOFILE= + ulimit -n ++ Number of File Descriptors + + +- LimitAS ++ LimitAS= + ulimit -v ++ Bytes + + +- LimitNPROC ++ LimitNPROC= + ulimit -u ++ Number of Processes + + +- LimitMEMLOCK ++ LimitMEMLOCK= + ulimit -l ++ Bytes + + +- LimitLOCKS ++ LimitLOCKS= + ulimit -x ++ Number of Locks + + +- LimitSIGPENDING ++ LimitSIGPENDING= + ulimit -i ++ Number of Queued Signals + + +- LimitMSGQUEUE ++ LimitMSGQUEUE= + ulimit -q ++ Bytes + + +- LimitNICE ++ LimitNICE= + ulimit -e ++ Nice Level + + +- LimitRTPRIO ++ LimitRTPRIO= + ulimit -r ++ Realtime Priority + + +- LimitRTTIME ++ LimitRTTIME= + No equivalent ++ Microseconds + + + +-
++ +
+ + +@@ -1266,6 +1309,7 @@ + systemd.mount5, + systemd.kill5, + systemd.resource-control5, ++ systemd.time7, + systemd.directives7, + tmpfiles.d5, + exec3 +diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 +index c3461a0..ce1397c 100644 +--- a/src/core/load-fragment-gperf.gperf.m4 ++++ b/src/core/load-fragment-gperf.gperf.m4 +@@ -58,7 +58,7 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0, + $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 + $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 + $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') +-$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) ++$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) + $1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) + $1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) + $1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +@@ -73,7 +73,7 @@ $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGP + $1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) + $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) + $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) +-$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) ++$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) + $1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs) + $1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs) + $1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index dbb45b2..8afe9d7 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1162,6 +1162,107 @@ int config_parse_bytes_limit(const char *unit, + return 0; + } + ++int config_parse_sec_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ ++ struct rlimit **rl = data; ++ rlim_t seconds; ++ int r; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ rl += ltype; ++ ++ if (streq(rvalue, "infinity")) ++ seconds = RLIM_INFINITY; ++ else { ++ usec_t t; ++ ++ r = parse_sec(rvalue, &t); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); ++ return 0; ++ } ++ ++ if (t == USEC_INFINITY) ++ seconds = RLIM_INFINITY; ++ else ++ seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); ++ } ++ ++ if (!*rl) { ++ *rl = new(struct rlimit, 1); ++ if (!*rl) ++ return log_oom(); ++ } ++ ++ (*rl)->rlim_cur = (*rl)->rlim_max = seconds; ++ return 0; ++} ++ ++ ++int config_parse_usec_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ ++ struct rlimit **rl = data; ++ rlim_t useconds; ++ int r; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ rl += ltype; ++ ++ if (streq(rvalue, "infinity")) ++ useconds = RLIM_INFINITY; ++ else { ++ usec_t t; ++ ++ r = parse_time(rvalue, &t, 1); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); ++ return 0; ++ } ++ ++ if (t == USEC_INFINITY) ++ useconds = RLIM_INFINITY; ++ else ++ useconds = (rlim_t) t; ++ } ++ ++ if (!*rl) { ++ *rl = new(struct rlimit, 1); ++ if (!*rl) ++ return log_oom(); ++ } ++ ++ (*rl)->rlim_cur = (*rl)->rlim_max = useconds; ++ return 0; ++} ++ + #ifdef HAVE_SYSV_COMPAT + int config_parse_sysv_priority(const char *unit, + const char *filename, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 2d509d0..359794d 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -57,6 +57,8 @@ int config_parse_exec_secure_bits(const char *unit, const char *filename, unsign + int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); ++int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 5500983..d151737 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -545,6 +545,66 @@ static void test_install_printf(void) { + expect(i4, "%U", "0"); + } + ++ ++static void test_config_parse_rlimit(void) { ++ struct rlimit * rl[_RLIMIT_MAX] = {}; ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); ++ ++ rl[RLIMIT_NOFILE] = free(rl[RLIMIT_NOFILE]); ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); ++ ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); ++ ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); ++ ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); ++ ++ rl[RLIMIT_CPU] = free(rl[RLIMIT_CPU]); ++ ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ ++ rl[RLIMIT_RTTIME] = free(rl[RLIMIT_RTTIME]); ++} ++ + int main(int argc, char *argv[]) { + int r; + +@@ -553,6 +613,7 @@ int main(int argc, char *argv[]) { + + r = test_unit_file_get_set(); + test_config_parse_exec(); ++ test_config_parse_rlimit(); + test_load_env_file_1(); + test_load_env_file_2(); + test_load_env_file_3(); diff --git a/SOURCES/0357-time-util-add-parse_time-which-is-like-parse_sec-but.patch b/SOURCES/0357-time-util-add-parse_time-which-is-like-parse_sec-but.patch new file mode 100644 index 0000000..6ef4d42 --- /dev/null +++ b/SOURCES/0357-time-util-add-parse_time-which-is-like-parse_sec-but.patch @@ -0,0 +1,214 @@ +From 8afe4259a8add0d042950015d34afc95a221ad96 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 6 Jul 2016 13:47:07 +0200 +Subject: [PATCH] time-util: add parse_time(), which is like parse_sec() but + allows specification of default time unit if none is specified +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is useful if we want to parse RLIMIT_RTTIME values where the common +UNIX syntax is without any units but refers to a non-second unit (µs in +this case), but where we want to allow specification of units. + +Cherry-picked from: 519cffec890510f817740d07355e911b10c203b7 +Related: #1351415 +--- + src/shared/calendarspec.c | 4 ++-- + src/shared/time-util.c | 34 ++++++++++++++++++++++------------ + src/shared/time-util.h | 1 + + src/test/test-time.c | 23 +++++++++++++++++++++++ + src/test/test-unit-file.c | 6 +++--- + 5 files changed, 51 insertions(+), 17 deletions(-) + +diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c +index 2fde3e1..abbf026 100644 +--- a/src/shared/calendarspec.c ++++ b/src/shared/calendarspec.c +@@ -556,7 +556,7 @@ static int parse_date(const char **p, CalendarSpec *c) { + return -EINVAL; + } + +-static int parse_time(const char **p, CalendarSpec *c) { ++static int parse_calendar_time(const char **p, CalendarSpec *c) { + CalendarComponent *h = NULL, *m = NULL, *s = NULL; + const char *t; + int r; +@@ -789,7 +789,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { + if (r < 0) + goto fail; + +- r = parse_time(&p, c); ++ r = parse_calendar_time(&p, c); + if (r < 0) + goto fail; + +diff --git a/src/shared/time-util.c b/src/shared/time-util.c +index 1c36c57..c001f52 100644 +--- a/src/shared/time-util.c ++++ b/src/shared/time-util.c +@@ -613,7 +613,8 @@ finish: + return 0; + } + +-int parse_sec(const char *t, usec_t *usec) { ++int parse_time(const char *t, usec_t *usec, usec_t default_unit) { ++ + static const struct { + const char *suffix; + usec_t usec; +@@ -645,7 +646,6 @@ int parse_sec(const char *t, usec_t *usec) { + { "y", USEC_PER_YEAR }, + { "usec", 1ULL }, + { "us", 1ULL }, +- { "", USEC_PER_SEC }, /* default is sec */ + }; + + const char *p, *s; +@@ -654,6 +654,7 @@ int parse_sec(const char *t, usec_t *usec) { + + assert(t); + assert(usec); ++ assert(default_unit > 0); + + p = t; + +@@ -672,6 +673,7 @@ int parse_sec(const char *t, usec_t *usec) { + long long l, z = 0; + char *e; + unsigned i, n = 0; ++ usec_t multiplier, k; + + p += strspn(p, WHITESPACE); + +@@ -714,21 +716,24 @@ int parse_sec(const char *t, usec_t *usec) { + + for (i = 0; i < ELEMENTSOF(table); i++) + if (startswith(e, table[i].suffix)) { +- usec_t k = (usec_t) z * table[i].usec; +- +- for (; n > 0; n--) +- k /= 10; +- +- r += (usec_t) l * table[i].usec + k; ++ multiplier = table[i].usec; + p = e + strlen(table[i].suffix); +- +- something = true; + break; + } + +- if (i >= ELEMENTSOF(table)) +- return -EINVAL; ++ if (i >= ELEMENTSOF(table)) { ++ multiplier = default_unit; ++ p = e; ++ } ++ ++ something = true; ++ ++ k = (usec_t) z * multiplier; ++ ++ for (; n > 0; n--) ++ k /= 10; + ++ r += (usec_t) l * multiplier + k; + } + + *usec = r; +@@ -736,6 +741,11 @@ int parse_sec(const char *t, usec_t *usec) { + return 0; + } + ++ ++int parse_sec(const char *t, usec_t *usec) { ++ return parse_time(t, usec, USEC_PER_SEC); ++} ++ + int parse_nsec(const char *t, nsec_t *nsec) { + static const struct { + const char *suffix; +diff --git a/src/shared/time-util.h b/src/shared/time-util.h +index fca8a4d..f278914 100644 +--- a/src/shared/time-util.h ++++ b/src/shared/time-util.h +@@ -99,6 +99,7 @@ void dual_timestamp_deserialize(const char *value, dual_timestamp *t); + int parse_timestamp(const char *t, usec_t *usec); + + int parse_sec(const char *t, usec_t *usec); ++int parse_time(const char *t, usec_t *usec, usec_t default_unit); + int parse_nsec(const char *t, nsec_t *nsec); + + bool ntp_synced(void); +diff --git a/src/test/test-time.c b/src/test/test-time.c +index 3840fff..820e4aa 100644 +--- a/src/test/test-time.c ++++ b/src/test/test-time.c +@@ -57,6 +57,28 @@ static void test_parse_sec(void) { + assert_se(parse_sec(".3 infinity", &u) < 0); + } + ++static void test_parse_time(void) { ++ usec_t u; ++ ++ assert_se(parse_time("5", &u, 1) >= 0); ++ assert_se(u == 5); ++ ++ assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0); ++ assert_se(u == 5 * USEC_PER_MSEC); ++ ++ assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0); ++ assert_se(u == 5 * USEC_PER_SEC); ++ ++ assert_se(parse_time("5s", &u, 1) >= 0); ++ assert_se(u == 5 * USEC_PER_SEC); ++ ++ assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0); ++ assert_se(u == 5 * USEC_PER_SEC); ++ ++ assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0); ++ assert_se(u == 5 * USEC_PER_SEC); ++} ++ + static void test_parse_nsec(void) { + nsec_t u; + +@@ -161,6 +183,7 @@ static void test_get_timezones(void) { + + int main(int argc, char *argv[]) { + test_parse_sec(); ++ test_parse_time(); + test_parse_nsec(); + test_format_timespan(1); + test_format_timespan(USEC_PER_MSEC); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index d151737..87c81cc 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -559,7 +559,7 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + +- rl[RLIMIT_NOFILE] = free(rl[RLIMIT_NOFILE]); ++ free(rl[RLIMIT_NOFILE]); + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); +@@ -580,7 +580,7 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + +- rl[RLIMIT_CPU] = free(rl[RLIMIT_CPU]); ++ free(rl[RLIMIT_CPU]); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); +@@ -602,7 +602,7 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + +- rl[RLIMIT_RTTIME] = free(rl[RLIMIT_RTTIME]); ++ free(rl[RLIMIT_RTTIME]); + } + + int main(int argc, char *argv[]) { diff --git a/SOURCES/0358-core-support-soft-hard-ranges-for-RLIMIT-options.patch b/SOURCES/0358-core-support-soft-hard-ranges-for-RLIMIT-options.patch new file mode 100644 index 0000000..fafaafe --- /dev/null +++ b/SOURCES/0358-core-support-soft-hard-ranges-for-RLIMIT-options.patch @@ -0,0 +1,1003 @@ +From 81a95ec724b7b874f850cb0f32f1981ccc4fb062 Mon Sep 17 00:00:00 2001 +From: Karel Zak +Date: Fri, 20 Nov 2015 12:54:10 +0100 +Subject: [PATCH] core: support ranges for RLIMIT options + +The new parser supports: + + - specify both limits to the same value + - specify both limits + +the size or time specific suffixes are supported, for example + + LimitRTTIME=1sec + LimitAS=4G:16G + +The patch introduces parse_rlimit_range() and rlim type (size, sec, +usec, etc.) specific parsers. No code is duplicated now. + +The patch also sync docs for DefaultLimitXXX= and LimitXXX=. + +References: https://github.com/systemd/systemd/issues/1769 + +Cherry-picked from: 91518d20ddf0376808544576d0ef0883cedc67d4 +Resolves: #1351415 +--- + man/systemd-system.conf.xml | 27 ++- + man/systemd.exec.xml | 5 +- + src/core/load-fragment.c | 243 ++++++++++++----------- + src/shared/util.c | 467 ++++++++++++++++++++++++++++++++++++++++++++ + src/shared/util.h | 14 ++ + src/test/test-unit-file.c | 31 +++ + 6 files changed, 667 insertions(+), 120 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index b7d9cde..39d19bc 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -326,13 +326,26 @@ + These settings control various default + resource limits for units. See + setrlimit2 +- for details. Use the string infinity to +- configure no limit on a specific resource. The multiplicative suffixes +- K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for +- resource limits measured in bytes (e.g. DefaultLimitAS=16G). These +- settings may be overridden in individual units using the corresponding +- LimitXXX= directives. Note that these resource limits are only +- defaults for units, they are not applied to PID 1 ++ for details. The resource limit is possible to specify in two formats, ++ to set soft and hard limits to the same value, ++ or to set both limits individually (e.g. DefaultLimitAS=4G:16G). ++ Use the string infinity to ++ configure no limit on a specific resource. The multiplicative ++ suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E ++ may be used for resource limits measured in bytes ++ (e.g. DefaultLimitAS=16G). For the limits referring to time values, ++ the usual time units ms, s, min, h and so on may be used (see ++ systemd.time7 ++ for details). Note that if no time unit is specified for ++ DefaultLimitCPU= the default unit of seconds is ++ implied, while for DefaultLimitRTTIME= the default ++ unit of microseconds is implied. Also, note that the effective ++ granularity of the limits might influence their ++ enforcement. For example, time limits specified for ++ DefaultLimitCPU= will be rounded up implicitly to ++ multiples of 1s. These settings may be overridden in individual units ++ using the corresponding LimitXXX= directives. Note that these resource ++ limits are only defaults for units, they are not applied to PID 1 + itself. + +
+diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index cfdcc3d..0cd469c 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -558,7 +558,10 @@ + These settings set both soft and hard limits + of various resources for executed processes. See + setrlimit2 +- for details. Use the string infinity to ++ for details. The resource limit is possible to specify in two formats, ++ to set soft and hard limits to the same value, ++ or to set both limits individually (e.g. LimitAS=4G:16G). ++ Use the string infinity to + configure no limit on a specific resource. The multiplicative + suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E + may be used for resource limits measured in bytes +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 8afe9d7..d307f1c 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1075,81 +1075,108 @@ int config_parse_bounding_set(const char *unit, + return 0; + } + +-int config_parse_limit(const char *unit, +- const char *filename, +- unsigned line, +- const char *section, +- unsigned section_line, +- const char *lvalue, +- int ltype, +- const char *rvalue, +- void *data, +- void *userdata) { + +- struct rlimit **rl = data; +- unsigned long long u; ++static int rlim_parse_u64(const char *val, rlim_t *res) { ++ int r = 0; + +- assert(filename); +- assert(lvalue); +- assert(rvalue); +- assert(data); ++ if (streq(val, "infinity")) ++ *res = RLIM_INFINITY; ++ else { ++ uint64_t u; + +- rl += ltype; ++ /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */ ++ assert_cc(sizeof(rlim_t) == sizeof(uint64_t)); ++ ++ r = safe_atou64(val, &u); ++ if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) ++ r = -ERANGE; ++ if (r == 0) ++ *res = (rlim_t) u; ++ } ++ return r; ++} + +- if (streq(rvalue, "infinity")) +- u = (unsigned long long) RLIM_INFINITY; ++static int rlim_parse_size(const char *val, rlim_t *res) { ++ int r = 0; ++ ++ if (streq(val, "infinity")) ++ *res = RLIM_INFINITY; + else { +- int r; ++ off_t u; + +- r = safe_atollu(rvalue, &u); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, -r, +- "Failed to parse resource value, ignoring: %s", rvalue); +- return 0; +- } ++ r = parse_size(val, 1024, &u); ++ if (r >= 0 && u >= (off_t) RLIM_INFINITY) ++ r = -ERANGE; ++ if (r == 0) ++ *res = (rlim_t) u; + } ++ return r; ++} + +- if (!*rl) { +- *rl = new(struct rlimit, 1); +- if (!*rl) +- return log_oom(); +- } ++static int rlim_parse_sec(const char *val, rlim_t *res) { ++ int r = 0; + +- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u; +- return 0; ++ if (streq(val, "infinity")) ++ *res = RLIM_INFINITY; ++ else { ++ usec_t t; ++ ++ r = parse_sec(val, &t); ++ if (r < 0) ++ return r; ++ if (t == USEC_INFINITY) ++ *res = RLIM_INFINITY; ++ else ++ *res = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); ++ ++ } ++ return r; + } + +-int config_parse_bytes_limit(const char *unit, +- const char *filename, +- unsigned line, +- const char *section, +- unsigned section_line, +- const char *lvalue, +- int ltype, +- const char *rvalue, +- void *data, +- void *userdata) { ++static int rlim_parse_usec(const char *val, rlim_t *res) { ++ int r = 0; + +- struct rlimit **rl = data; +- uint64_t bytes; ++ if (streq(val, "infinity")) ++ *res = RLIM_INFINITY; ++ else { ++ usec_t t; + +- assert(filename); +- assert(lvalue); +- assert(rvalue); +- assert(data); ++ r = parse_time(val, &t, 1); ++ if (r < 0) ++ return r; ++ if (t == USEC_INFINITY) ++ *res = RLIM_INFINITY; ++ else ++ *res = (rlim_t) t; ++ } ++ return r; ++} + +- rl += ltype; ++static int parse_rlimit_range( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *value, ++ struct rlimit **rl, ++ int (*rlim_parser)(const char *, rlim_t *)) { + +- if (streq(rvalue, "infinity")) +- bytes = (uint64_t) RLIM_INFINITY; +- else { +- int r; ++ rlim_t soft, hard; ++ _cleanup_free_ char *sword = NULL, *hword = NULL; ++ int nwords, r; + +- r = parse_size(rvalue, 1024, &bytes); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); +- return 0; +- } ++ assert(value); ++ ++ /* or */ ++ nwords = extract_many_words(&value, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &sword, &hword, NULL); ++ r = nwords < 0 ? nwords : nwords == 0 ? -EINVAL : 0; ++ ++ if (r == 0) ++ r = rlim_parser(sword, &soft); ++ if (r == 0 && nwords == 2) ++ r = rlim_parser(hword, &hard); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", value); ++ return 0; + } + + if (!*rl) { +@@ -1157,12 +1184,12 @@ int config_parse_bytes_limit(const char *unit, + if (!*rl) + return log_oom(); + } +- +- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) bytes; ++ (*rl)->rlim_cur = soft; ++ (*rl)->rlim_max = nwords == 2 ? hard : soft; + return 0; + } + +-int config_parse_sec_limit( ++int config_parse_limit( + const char *unit, + const char *filename, + unsigned line, +@@ -1175,8 +1202,6 @@ int config_parse_sec_limit( + void *userdata) { + + struct rlimit **rl = data; +- rlim_t seconds; +- int r; + + assert(filename); + assert(lvalue); +@@ -1184,36 +1209,33 @@ int config_parse_sec_limit( + assert(data); + + rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_u64); ++} + +- if (streq(rvalue, "infinity")) +- seconds = RLIM_INFINITY; +- else { +- usec_t t; +- +- r = parse_sec(rvalue, &t); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); +- return 0; +- } ++int config_parse_bytes_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { + +- if (t == USEC_INFINITY) +- seconds = RLIM_INFINITY; +- else +- seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); +- } ++ struct rlimit **rl = data; + +- if (!*rl) { +- *rl = new(struct rlimit, 1); +- if (!*rl) +- return log_oom(); +- } ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); + +- (*rl)->rlim_cur = (*rl)->rlim_max = seconds; +- return 0; ++ rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_size); + } + +- +-int config_parse_usec_limit( ++int config_parse_sec_limit( + const char *unit, + const char *filename, + unsigned line, +@@ -1226,8 +1248,6 @@ int config_parse_usec_limit( + void *userdata) { + + struct rlimit **rl = data; +- rlim_t useconds; +- int r; + + assert(filename); + assert(lvalue); +@@ -1235,34 +1255,33 @@ int config_parse_usec_limit( + assert(data); + + rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_sec); ++} + +- if (streq(rvalue, "infinity")) +- useconds = RLIM_INFINITY; +- else { +- usec_t t; +- +- r = parse_time(rvalue, &t, 1); +- if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); +- return 0; +- } ++int config_parse_usec_limit( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { + +- if (t == USEC_INFINITY) +- useconds = RLIM_INFINITY; +- else +- useconds = (rlim_t) t; +- } ++ struct rlimit **rl = data; + +- if (!*rl) { +- *rl = new(struct rlimit, 1); +- if (!*rl) +- return log_oom(); +- } ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); + +- (*rl)->rlim_cur = (*rl)->rlim_max = useconds; +- return 0; ++ rl += ltype; ++ return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec); + } + ++ + #ifdef HAVE_SYSV_COMPAT + int config_parse_sysv_priority(const char *unit, + const char *filename, +diff --git a/src/shared/util.c b/src/shared/util.c +index 036677e..f75ed9d 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -93,6 +93,7 @@ + #include "virt.h" + #include "def.h" + #include "sparse-endian.h" ++#include "conf-parser.h" + + int saved_argc = 0; + char **saved_argv = NULL; +@@ -100,6 +101,8 @@ char **saved_argv = NULL; + static volatile unsigned cached_columns = 0; + static volatile unsigned cached_lines = 0; + ++bool unichar_is_valid(int32_t ch); ++ + size_t page_size(void) { + static thread_local size_t pgsz = 0; + long r; +@@ -1365,6 +1368,207 @@ char *cescape(const char *s) { + return r; + } + ++bool unichar_is_valid(int32_t ch) { ++ ++ if (ch >= 0x110000) /* End of unicode space */ ++ return false; ++ if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ ++ return false; ++ if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ ++ return false; ++ if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ ++ return false; ++ ++ return true; ++} ++ ++int cunescape_one(const char *p, size_t length, int32_t *ret, bool *eight_bit) { ++ int r = 1; ++ ++ assert(p); ++ assert(*p); ++ assert(ret); ++ ++ /* Unescapes C style. Returns the unescaped character in ret. ++ * Sets *eight_bit to true if the escaped sequence either fits in ++ * one byte in UTF-8 or is a non-unicode literal byte and should ++ * instead be copied directly. ++ */ ++ ++ if (length != (size_t) -1 && length < 1) ++ return -EINVAL; ++ ++ switch (p[0]) { ++ ++ case 'a': ++ *ret = '\a'; ++ break; ++ case 'b': ++ *ret = '\b'; ++ break; ++ case 'f': ++ *ret = '\f'; ++ break; ++ case 'n': ++ *ret = '\n'; ++ break; ++ case 'r': ++ *ret = '\r'; ++ break; ++ case 't': ++ *ret = '\t'; ++ break; ++ case 'v': ++ *ret = '\v'; ++ break; ++ case '\\': ++ *ret = '\\'; ++ break; ++ case '"': ++ *ret = '"'; ++ break; ++ case '\'': ++ *ret = '\''; ++ break; ++ ++ case 's': ++ /* This is an extension of the XDG syntax files */ ++ *ret = ' '; ++ break; ++ ++ case 'x': { ++ /* hexadecimal encoding */ ++ int a, b; ++ ++ if (length != (size_t) -1 && length < 3) ++ return -EINVAL; ++ ++ a = unhexchar(p[1]); ++ if (a < 0) ++ return -EINVAL; ++ ++ b = unhexchar(p[2]); ++ if (b < 0) ++ return -EINVAL; ++ ++ /* Don't allow NUL bytes */ ++ if (a == 0 && b == 0) ++ return -EINVAL; ++ ++ *ret = (a << 4U) | b; ++ *eight_bit = true; ++ r = 3; ++ break; ++ } ++ ++ case 'u': { ++ /* C++11 style 16bit unicode */ ++ ++ int a[4]; ++ unsigned i; ++ uint32_t c; ++ ++ if (length != (size_t) -1 && length < 5) ++ return -EINVAL; ++ ++ for (i = 0; i < 4; i++) { ++ a[i] = unhexchar(p[1 + i]); ++ if (a[i] < 0) ++ return a[i]; ++ } ++ ++ c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; ++ ++ /* Don't allow 0 chars */ ++ if (c == 0) ++ return -EINVAL; ++ ++ *ret = c; ++ r = 5; ++ break; ++ } ++ ++ case 'U': { ++ /* C++11 style 32bit unicode */ ++ ++ int a[8]; ++ unsigned i; ++ int32_t c; ++ ++ if (length != (size_t) -1 && length < 9) ++ return -EINVAL; ++ ++ for (i = 0; i < 8; i++) { ++ a[i] = unhexchar(p[1 + i]); ++ if (a[i] < 0) ++ return a[i]; ++ } ++ ++ c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) | ++ ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; ++ ++ /* Don't allow 0 chars */ ++ if (c == 0) ++ return -EINVAL; ++ ++ /* Don't allow invalid code points */ ++ if (!unichar_is_valid(c)) ++ return -EINVAL; ++ ++ *ret = c; ++ r = 9; ++ break; ++ } ++ ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': { ++ /* octal encoding */ ++ int a, b, c; ++ int32_t m; ++ ++ if (length != (size_t) -1 && length < 3) ++ return -EINVAL; ++ ++ a = unoctchar(p[0]); ++ if (a < 0) ++ return -EINVAL; ++ ++ b = unoctchar(p[1]); ++ if (b < 0) ++ return -EINVAL; ++ ++ c = unoctchar(p[2]); ++ if (c < 0) ++ return -EINVAL; ++ ++ /* don't allow NUL bytes */ ++ if (a == 0 && b == 0 && c == 0) ++ return -EINVAL; ++ ++ /* Don't allow bytes above 255 */ ++ m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c; ++ if (m > 255) ++ return -EINVAL; ++ ++ *ret = m; ++ *eight_bit = true; ++ r = 3; ++ break; ++ } ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return r; ++} ++ + char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) { + char *r, *t; + const char *f; +@@ -8207,3 +8411,266 @@ bool colors_enabled(void) { + + return parse_boolean(colors) != 0; + } ++ ++int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { ++ _cleanup_free_ char *s = NULL; ++ size_t allocated = 0, sz = 0; ++ char c; ++ int r; ++ ++ char quote = 0; /* 0 or ' or " */ ++ bool backslash = false; /* whether we've just seen a backslash */ ++ ++ assert(p); ++ assert(ret); ++ ++ /* Bail early if called after last value or with no input */ ++ if (!*p) ++ goto finish_force_terminate; ++ c = **p; ++ ++ if (!separators) ++ separators = WHITESPACE; ++ ++ /* Parses the first word of a string, and returns it in ++ * *ret. Removes all quotes in the process. When parsing fails ++ * (because of an uneven number of quotes or similar), leaves ++ * the pointer *p at the first invalid character. */ ++ ++ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) ++ if (!GREEDY_REALLOC(s, allocated, sz+1)) ++ return -ENOMEM; ++ ++ for (;; (*p)++, c = **p) { ++ if (c == 0) ++ goto finish_force_terminate; ++ else if (strchr(separators, c)) { ++ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { ++ (*p)++; ++ goto finish_force_next; ++ } ++ } else { ++ /* We found a non-blank character, so we will always ++ * want to return a string (even if it is empty), ++ * allocate it here. */ ++ if (!GREEDY_REALLOC(s, allocated, sz+1)) ++ return -ENOMEM; ++ break; ++ } ++ } ++ ++ for (;; (*p)++, c = **p) { ++ if (backslash) { ++ if (!GREEDY_REALLOC(s, allocated, sz+7)) ++ return -ENOMEM; ++ ++ if (c == 0) { ++ if ((flags & EXTRACT_CUNESCAPE_RELAX) && ++ (!quote || flags & EXTRACT_RELAX)) { ++ /* If we find an unquoted trailing backslash and we're in ++ * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the ++ * output. ++ * ++ * Unbalanced quotes will only be allowed in EXTRACT_RELAX ++ * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. ++ */ ++ s[sz++] = '\\'; ++ goto finish_force_terminate; ++ } ++ if (flags & EXTRACT_RELAX) ++ goto finish_force_terminate; ++ return -EINVAL; ++ } ++ ++ if (flags & EXTRACT_CUNESCAPE) { ++ bool eight_bit = false; ++ int32_t u; ++ ++ r = cunescape_one(*p, (size_t) -1, &u, &eight_bit); ++ if (r < 0) { ++ if (flags & EXTRACT_CUNESCAPE_RELAX) { ++ s[sz++] = '\\'; ++ s[sz++] = c; ++ } else ++ return -EINVAL; ++ } else { ++ (*p) += r - 1; ++ ++ if (eight_bit) ++ s[sz++] = u; ++ else ++ sz += utf8_encode_unichar(s + sz, u); ++ } ++ } else ++ s[sz++] = c; ++ ++ backslash = false; ++ ++ } else if (quote) { /* inside either single or double quotes */ ++ for (;; (*p)++, c = **p) { ++ if (c == 0) { ++ if (flags & EXTRACT_RELAX) ++ goto finish_force_terminate; ++ return -EINVAL; ++ } else if (c == quote) { /* found the end quote */ ++ quote = 0; ++ break; ++ } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) { ++ backslash = true; ++ break; ++ } else { ++ if (!GREEDY_REALLOC(s, allocated, sz+2)) ++ return -ENOMEM; ++ ++ s[sz++] = c; ++ } ++ } ++ ++ } else { ++ for (;; (*p)++, c = **p) { ++ if (c == 0) ++ goto finish_force_terminate; ++ else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) { ++ quote = c; ++ break; ++ } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) { ++ backslash = true; ++ break; ++ } else if (strchr(separators, c)) { ++ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { ++ (*p)++; ++ goto finish_force_next; ++ } ++ /* Skip additional coalesced separators. */ ++ for (;; (*p)++, c = **p) { ++ if (c == 0) ++ goto finish_force_terminate; ++ if (!strchr(separators, c)) ++ break; ++ } ++ goto finish; ++ ++ } else { ++ if (!GREEDY_REALLOC(s, allocated, sz+2)) ++ return -ENOMEM; ++ ++ s[sz++] = c; ++ } ++ } ++ } ++ } ++ ++finish_force_terminate: ++ *p = NULL; ++finish: ++ if (!s) { ++ *p = NULL; ++ *ret = NULL; ++ return 0; ++ } ++ ++finish_force_next: ++ s[sz] = 0; ++ *ret = s; ++ s = NULL; ++ ++ return 1; ++} ++ ++int extract_first_word_and_warn( ++ const char **p, ++ char **ret, ++ const char *separators, ++ ExtractFlags flags, ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *rvalue) { ++ ++ /* Try to unquote it, if it fails, warn about it and try again ++ * but this time using EXTRACT_CUNESCAPE_RELAX to keep the ++ * backslashes verbatim in invalid escape sequences. */ ++ ++ const char *save; ++ int r; ++ ++ save = *p; ++ r = extract_first_word(p, ret, separators, flags); ++ if (r >= 0) ++ return r; ++ ++ if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) { ++ ++ /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ ++ *p = save; ++ r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); ++ if (r >= 0) { ++ /* It worked this time, hence it must have been an invalid escape sequence we could correct. */ ++ log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue); ++ return r; ++ } ++ ++ /* If it's still EINVAL; then it must be unbalanced quoting, report this. */ ++ if (r == -EINVAL) ++ return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue); ++ } ++ ++ /* Can be any error, report it */ ++ return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue); ++} ++ ++int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { ++ va_list ap; ++ char **l; ++ int n = 0, i, c, r; ++ ++ /* Parses a number of words from a string, stripping any ++ * quotes if necessary. */ ++ ++ assert(p); ++ ++ /* Count how many words are expected */ ++ va_start(ap, flags); ++ for (;;) { ++ if (!va_arg(ap, char **)) ++ break; ++ n++; ++ } ++ va_end(ap); ++ ++ if (n <= 0) ++ return 0; ++ ++ /* Read all words into a temporary array */ ++ l = newa0(char*, n); ++ for (c = 0; c < n; c++) { ++ ++ r = extract_first_word(p, &l[c], separators, flags); ++ if (r < 0) { ++ int j; ++ ++ for (j = 0; j < c; j++) ++ free(l[j]); ++ ++ return r; ++ } ++ ++ if (r == 0) ++ break; ++ } ++ ++ /* If we managed to parse all words, return them in the passed ++ * in parameters */ ++ va_start(ap, flags); ++ for (i = 0; i < n; i++) { ++ char **v; ++ ++ v = va_arg(ap, char **); ++ assert(v); ++ ++ *v = l[i]; ++ } ++ va_end(ap); ++ ++ return c; ++} +diff --git a/src/shared/util.h b/src/shared/util.h +index a441e44..be04524 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -315,6 +315,7 @@ int undecchar(char c) _const_; + char *cescape(const char *s); + char *cunescape(const char *s); + char *cunescape_length(const char *s, size_t length); ++int cunescape_one(const char *p, size_t length, int32_t *ret, bool *eight_bit); + char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix); + + char *xescape(const char *s, const char *bad); +@@ -1082,3 +1083,16 @@ void sigkill_wait(pid_t *pid); + int syslog_parse_priority(const char **p, int *priority, bool with_facility); + + char *shell_maybe_quote(const char *s); ++ ++typedef enum ExtractFlags { ++ EXTRACT_RELAX = 1, ++ EXTRACT_CUNESCAPE = 2, ++ EXTRACT_CUNESCAPE_RELAX = 4, ++ EXTRACT_QUOTES = 8, ++ EXTRACT_DONT_COALESCE_SEPARATORS = 16, ++ EXTRACT_RETAIN_ESCAPE = 32, ++} ExtractFlags; ++ ++int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); ++int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); ++int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 87c81cc..931dfed 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -554,11 +554,22 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66); ++ + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); ++ + free(rl[RLIMIT_NOFILE]); + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); +@@ -570,6 +581,11 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + ++ assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_CPU]); ++ assert_se(rl[RLIMIT_CPU]->rlim_cur == 40); ++ assert_se(rl[RLIMIT_CPU]->rlim_max == 60); ++ + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); +@@ -587,16 +603,31 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60); ++ + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC); ++ + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + ++ assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_RTTIME]); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); ++ assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); ++ + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); diff --git a/SOURCES/0359-core-fix-rlimit-parsing.patch b/SOURCES/0359-core-fix-rlimit-parsing.patch new file mode 100644 index 0000000..42fe56a --- /dev/null +++ b/SOURCES/0359-core-fix-rlimit-parsing.patch @@ -0,0 +1,74 @@ +From b53ec8d7dca8eba189c45ae29e4d5ff03e5e5556 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 27 Nov 2015 08:54:42 +0000 +Subject: [PATCH] core: fix rlimit parsing + +* refuse limits if soft > hard +* print an actual value instead of (null) + +see https://github.com/systemd/systemd/pull/1994#issuecomment-159999123 + +Cherry-picked from: 0316f2aeebde7569d24a93ab788ac4bc1657b11b +Related: #1351415 +--- + src/core/load-fragment.c | 5 ++++- + src/test/test-unit-file.c | 21 +++++++++++++++++++++ + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index d307f1c..2f6209e 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -1160,6 +1160,7 @@ static int parse_rlimit_range( + struct rlimit **rl, + int (*rlim_parser)(const char *, rlim_t *)) { + ++ const char *whole_value = value; + rlim_t soft, hard; + _cleanup_free_ char *sword = NULL, *hword = NULL; + int nwords, r; +@@ -1175,9 +1176,11 @@ static int parse_rlimit_range( + if (r == 0 && nwords == 2) + r = rlim_parser(hword, &hard); + if (r < 0) { +- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", value); ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", whole_value); + return 0; + } ++ if (nwords == 2 && soft > hard) ++ return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid resource value ("RLIM_FMT" > "RLIM_FMT"), ignoring: %s", soft, hard, whole_value); + + if (!*rl) { + *rl = new(struct rlimit, 1); +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index 931dfed..8acf071 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -570,6 +570,27 @@ static void test_config_parse_rlimit(void) { + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); ++ ++ /* Invalid values don't change rl */ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); ++ ++ assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0); ++ assert_se(rl[RLIMIT_NOFILE]); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); ++ assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); ++ + free(rl[RLIMIT_NOFILE]); + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); diff --git a/SOURCES/0360-core-dump-rlim_cur-too.patch b/SOURCES/0360-core-dump-rlim_cur-too.patch new file mode 100644 index 0000000..e9a5db3 --- /dev/null +++ b/SOURCES/0360-core-dump-rlim_cur-too.patch @@ -0,0 +1,26 @@ +From 0c4a5153b14701ffdbff2f768548d4a657b1ca9f Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Fri, 27 Nov 2015 09:13:35 +0000 +Subject: [PATCH] core: dump rlim_cur too + +Cherry-picked from: fdbbadbd0d13d3296b9aa4273aaeecd9ba6b82d1 +Related: #1351415 +--- + src/core/execute.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 8172c8b..e9b4359 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -2254,8 +2254,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { + + for (i = 0; i < RLIM_NLIMITS; i++) + if (c->rlimit[i]) +- fprintf(f, "%s%s: "RLIM_FMT"\n", +- prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max); ++ fprintf(f, "%s%s: " RLIM_FMT " " RLIM_FMT "\n", ++ prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur, c->rlimit[i]->rlim_max); + + if (c->ioprio_set) { + _cleanup_free_ char *class_str = NULL; diff --git a/SOURCES/0361-install-fix-disable-via-unit-file-path.patch b/SOURCES/0361-install-fix-disable-via-unit-file-path.patch new file mode 100644 index 0000000..ae0acdf --- /dev/null +++ b/SOURCES/0361-install-fix-disable-via-unit-file-path.patch @@ -0,0 +1,39 @@ +From 96df052a6a9d09cde2d437861727bf37fe6446b4 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 12 Jul 2016 09:40:02 +0200 +Subject: [PATCH] install: fix disable via unit file path + +Drop the check for unit file name validity. install_info_add does that +anyway. Also pass NULL in place of name argument to install_info_add if +we are dealing with path to a unit file. install_info_add will figure +out a name from a path and it will correctly populate +UnitFileInstallInfo with both name and path. Then in +unit_file_search called from install_info_traverse we can take a +shortcut and attempt to load unit file directly. + +Cherry-picked from: 4dfbf0b176ff0e8a352617eba5e79065ee477969 +Resolves: #1348208 +--- + src/shared/install.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 5288bb4..f190dbf 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1910,10 +1910,12 @@ int unit_file_disable( + return r; + + STRV_FOREACH(i, files) { +- if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) +- return -EINVAL; + +- r = install_info_add(&c, *i, NULL, NULL); ++ if (!is_path(*i)) ++ r = install_info_add(&c, *i, NULL, NULL); ++ else ++ r = install_info_add(&c, NULL, *i, NULL); ++ + if (r < 0) + return r; + } diff --git a/SOURCES/0362-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch b/SOURCES/0362-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch new file mode 100644 index 0000000..0eb22d0 --- /dev/null +++ b/SOURCES/0362-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch @@ -0,0 +1,248 @@ +From fd8580a8f42b1e10d75f43229b203fb889260b71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Sat, 16 Jul 2016 21:04:13 +0200 +Subject: [PATCH] manager: don't skip sigchld handler for main and control pid + for services (#3738) + +During stop when service has one "regular" pid one main pid and one +control pid and the sighld for the regular one is processed first the +unit_tidy_watch_pids will skip the main and control pid and does not +remove them from u->pids(). But then we skip the sigchld event because we +already did one in the iteration and there are two pids in u->pids. + +v2: Use general unit_main_pid() and unit_control_pid() instead of +reaching directly to service structure. +Cherry-picked from: ccc2c98e1b0c06861577632440b996ca16cefd53 +Resolves: #1342173 +--- + src/core/busname.c | 10 ++++++++++ + src/core/manager.c | 5 ++++- + src/core/mount.c | 10 ++++++++++ + src/core/service.c | 19 +++++++++++++++++++ + src/core/socket.c | 10 ++++++++++ + src/core/swap.c | 10 ++++++++++ + src/core/unit.c | 18 ++++++++++++++++++ + src/core/unit.h | 9 +++++++++ + 8 files changed, 90 insertions(+), 1 deletion(-) + +diff --git a/src/core/busname.c b/src/core/busname.c +index 43d7607..f626ba9 100644 +--- a/src/core/busname.c ++++ b/src/core/busname.c +@@ -997,6 +997,14 @@ static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); + ++static int busname_control_pid(Unit *u) { ++ BusName *n = BUSNAME(u); ++ ++ assert(n); ++ ++ return n->control_pid; ++} ++ + static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { + [BUSNAME_SUCCESS] = "success", + [BUSNAME_FAILURE_RESOURCES] = "resources", +@@ -1047,6 +1055,8 @@ const UnitVTable busname_vtable = { + + .supported = busname_supported, + ++ .control_pid = busname_control_pid, ++ + .bus_interface = "org.freedesktop.systemd1.BusName", + .bus_vtable = bus_busname_vtable, + +diff --git a/src/core/manager.c b/src/core/manager.c +index d168777..5da8365 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1760,7 +1760,10 @@ static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { + unit_unwatch_pid(u, si->si_pid); + + if (UNIT_VTABLE(u)->sigchld_event) { +- if (set_size(u->pids) <= 1 || iteration != u->sigchldgen) { ++ if (set_size(u->pids) <= 1 || ++ iteration != u->sigchldgen || ++ unit_main_pid(u) == si->si_pid || ++ unit_control_pid(u) == si->si_pid) { + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); + u->sigchldgen = iteration; + } else +diff --git a/src/core/mount.c b/src/core/mount.c +index fe967bc..3fbdb7d 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1877,6 +1877,14 @@ static const char* const mount_state_table[_MOUNT_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); + ++static int mount_control_pid(Unit *u) { ++ Mount *m = MOUNT(u); ++ ++ assert(m); ++ ++ return m->control_pid; ++} ++ + static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { + [MOUNT_EXEC_MOUNT] = "ExecMount", + [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", +@@ -1938,6 +1946,8 @@ const UnitVTable mount_vtable = { + + .reset_failed = mount_reset_failed, + ++ .control_pid = mount_control_pid, ++ + .bus_interface = "org.freedesktop.systemd1.Mount", + .bus_vtable = bus_mount_vtable, + .bus_set_property = bus_mount_set_property, +diff --git a/src/core/service.c b/src/core/service.c +index c76713b..babd3c5 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -3068,6 +3068,22 @@ static const char* const service_state_table[_SERVICE_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); + ++static int service_main_pid(Unit *u) { ++ Service *s = SERVICE(u); ++ ++ assert(s); ++ ++ return s->main_pid; ++} ++ ++static int service_control_pid(Unit *u) { ++ Service *s = SERVICE(u); ++ ++ assert(s); ++ ++ return s->control_pid; ++} ++ + static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { + [SERVICE_RESTART_NO] = "no", + [SERVICE_RESTART_ON_SUCCESS] = "on-success", +@@ -3178,6 +3194,9 @@ const UnitVTable service_vtable = { + .notify_cgroup_empty = service_notify_cgroup_empty_event, + .notify_message = service_notify_message, + ++ .main_pid = service_main_pid, ++ .control_pid = service_control_pid, ++ + .bus_name_owner_change = service_bus_name_owner_change, + + .bus_interface = "org.freedesktop.systemd1.Service", +diff --git a/src/core/socket.c b/src/core/socket.c +index bc677a2..771af0d 100644 +--- a/src/core/socket.c ++++ b/src/core/socket.c +@@ -2648,6 +2648,14 @@ static const char* const socket_state_table[_SOCKET_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); + ++static int socket_control_pid(Unit *u) { ++ Socket *s = SOCKET(u); ++ ++ assert(s); ++ ++ return s->control_pid; ++} ++ + static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { + [SOCKET_EXEC_START_PRE] = "StartPre", + [SOCKET_EXEC_START_CHOWN] = "StartChown", +@@ -2713,6 +2721,8 @@ const UnitVTable socket_vtable = { + + .reset_failed = socket_reset_failed, + ++ .control_pid = socket_control_pid, ++ + .bus_interface = "org.freedesktop.systemd1.Socket", + .bus_vtable = bus_socket_vtable, + .bus_set_property = bus_socket_set_property, +diff --git a/src/core/swap.c b/src/core/swap.c +index 34a2c40..42f9959 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -1426,6 +1426,14 @@ static const char* const swap_state_table[_SWAP_STATE_MAX] = { + + DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); + ++static int swap_control_pid(Unit *u) { ++ Swap *s = SWAP(u); ++ ++ assert(s); ++ ++ return s->control_pid; ++} ++ + static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { + [SWAP_EXEC_ACTIVATE] = "ExecActivate", + [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", +@@ -1487,6 +1495,8 @@ const UnitVTable swap_vtable = { + + .reset_failed = swap_reset_failed, + ++ .control_pid = swap_control_pid, ++ + .bus_interface = "org.freedesktop.systemd1.Swap", + .bus_vtable = bus_swap_vtable, + .bus_set_property = bus_swap_set_property, +diff --git a/src/core/unit.c b/src/core/unit.c +index d62135d..0e90d13 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3674,6 +3674,24 @@ int unit_setup_exec_runtime(Unit *u) { + return exec_runtime_make(rt, unit_get_exec_context(u), u->id); + } + ++pid_t unit_control_pid(Unit *u) { ++ assert(u); ++ ++ if (UNIT_VTABLE(u)->control_pid) ++ return UNIT_VTABLE(u)->control_pid(u); ++ ++ return 0; ++} ++ ++pid_t unit_main_pid(Unit *u) { ++ assert(u); ++ ++ if (UNIT_VTABLE(u)->main_pid) ++ return UNIT_VTABLE(u)->main_pid(u); ++ ++ return 0; ++} ++ + static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { + [UNIT_ACTIVE] = "active", + [UNIT_RELOADING] = "reloading", +diff --git a/src/core/unit.h b/src/core/unit.h +index d936457..35287a5 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -399,6 +399,12 @@ struct UnitVTable { + + int (*get_timeout)(Unit *u, uint64_t *timeout); + ++ /* Returns the main PID if there is any defined, or 0. */ ++ pid_t (*main_pid)(Unit *u); ++ ++ /* Returns the main PID if there is any defined, or 0. */ ++ pid_t (*control_pid)(Unit *u); ++ + /* This is called for each unit type and should be used to + * enumerate existing devices and load them. However, + * everything that is loaded here should still stay in +@@ -610,6 +616,9 @@ int unit_make_transient(Unit *u); + + int unit_require_mounts_for(Unit *u, const char *path); + ++pid_t unit_control_pid(Unit *u); ++pid_t unit_main_pid(Unit *u); ++ + const char *unit_active_state_to_string(UnitActiveState i) _const_; + UnitActiveState unit_active_state_from_string(const char *s) _pure_; + diff --git a/SOURCES/0363-units-increase-watchdog-timeout-to-3min-for-all-our-.patch b/SOURCES/0363-units-increase-watchdog-timeout-to-3min-for-all-our-.patch new file mode 100644 index 0000000..5c97603 --- /dev/null +++ b/SOURCES/0363-units-increase-watchdog-timeout-to-3min-for-all-our-.patch @@ -0,0 +1,156 @@ +From 5be84b3ae46c0fd35c3e80d4f457bf5aedc8af8f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 23 Sep 2015 17:27:39 +0200 +Subject: [PATCH] units: increase watchdog timeout to 3min for all our services + +Apparently, disk IO issues are more frequent than we hope, and 1min +waiting for disk IO happens, so let's increase the watchdog timeout a +bit, for all our services. + +See #1353 for an example where this triggers. + +(cherry picked from commit c2fc2c2560f0ca0fab383753c065e45d76f465e5) +Resolves: #1267707 +--- + units/systemd-hostnamed.service.in | 2 +- + units/systemd-importd.service.in | 2 +- + units/systemd-journald.service.in | 2 +- + units/systemd-localed.service.in | 2 +- + units/systemd-logind.service.in | 2 +- + units/systemd-machined.service.in | 2 +- + units/systemd-networkd.service.in | 2 +- + units/systemd-resolved.service.m4.in | 2 +- + units/systemd-timedated.service.in | 2 +- + units/systemd-timesyncd.service.in | 2 +- + 10 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in +index cc88ecd..b7079e4 100644 +--- a/units/systemd-hostnamed.service.in ++++ b/units/systemd-hostnamed.service.in +@@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/hostnamed + ExecStart=@rootlibexecdir@/systemd-hostnamed + BusName=org.freedesktop.hostname1 + CapabilityBoundingSet=CAP_SYS_ADMIN +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + PrivateDevices=yes + PrivateNetwork=yes +diff --git a/units/systemd-importd.service.in b/units/systemd-importd.service.in +index 5534a49..60e8e9c 100644 +--- a/units/systemd-importd.service.in ++++ b/units/systemd-importd.service.in +@@ -14,7 +14,7 @@ ExecStart=@rootlibexecdir@/systemd-importd + BusName=org.freedesktop.import1 + CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_SYS_ADMIN CAP_SETPCAP + NoNewPrivileges=yes +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + ProtectSystem=full + ProtectHome=yes +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index 9d44622..8575912 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -22,7 +22,7 @@ RestartSec=0 + NotifyAccess=all + StandardOutput=null + CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE +-WatchdogSec=1min ++WatchdogSec=3min + + # Increase the default a bit in order to allow many simultaneous + # services being run since we keep one fd open per service. Also, when +diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in +index bfa0978..9b13f90 100644 +--- a/units/systemd-localed.service.in ++++ b/units/systemd-localed.service.in +@@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/localed + ExecStart=@rootlibexecdir@/systemd-localed + BusName=org.freedesktop.locale1 + CapabilityBoundingSet= +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + PrivateDevices=yes + PrivateNetwork=yes +diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in +index f087e99..ff04913 100644 +--- a/units/systemd-logind.service.in ++++ b/units/systemd-logind.service.in +@@ -24,7 +24,7 @@ Restart=always + RestartSec=0 + BusName=org.freedesktop.login1 + CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG +-WatchdogSec=1min ++WatchdogSec=3min + + # Increase the default a bit in order to allow many simultaneous + # logins since we keep one fd open per session. +diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in +index 15f34d9..35cde98 100644 +--- a/units/systemd-machined.service.in ++++ b/units/systemd-machined.service.in +@@ -16,7 +16,7 @@ After=machine.slice + ExecStart=@rootlibexecdir@/systemd-machined + BusName=org.freedesktop.machine1 + CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + PrivateDevices=yes + PrivateNetwork=yes +diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in +index 5a91b8e..d3808c4 100644 +--- a/units/systemd-networkd.service.in ++++ b/units/systemd-networkd.service.in +@@ -25,7 +25,7 @@ ExecStart=@rootlibexecdir@/systemd-networkd + CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER + ProtectSystem=full + ProtectHome=yes +-WatchdogSec=1min ++WatchdogSec=3min + + [Install] + WantedBy=multi-user.target +diff --git a/units/systemd-resolved.service.m4.in b/units/systemd-resolved.service.m4.in +index 98ae564..46864e6 100644 +--- a/units/systemd-resolved.service.m4.in ++++ b/units/systemd-resolved.service.m4.in +@@ -25,7 +25,7 @@ ExecStart=@rootlibexecdir@/systemd-resolved + CapabilityBoundingSet=CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER + ProtectSystem=full + ProtectHome=yes +-WatchdogSec=1min ++WatchdogSec=3min + + [Install] + WantedBy=multi-user.target +diff --git a/units/systemd-timedated.service.in b/units/systemd-timedated.service.in +index fe5ccb4..0c9599d 100644 +--- a/units/systemd-timedated.service.in ++++ b/units/systemd-timedated.service.in +@@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/timedated + ExecStart=@rootlibexecdir@/systemd-timedated + BusName=org.freedesktop.timedate1 + CapabilityBoundingSet=CAP_SYS_TIME +-WatchdogSec=1min ++WatchdogSec=3min + PrivateTmp=yes + ProtectSystem=yes + ProtectHome=yes +diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in +index 39edafc..c7d1d2b 100644 +--- a/units/systemd-timesyncd.service.in ++++ b/units/systemd-timesyncd.service.in +@@ -27,7 +27,7 @@ PrivateTmp=yes + PrivateDevices=yes + ProtectSystem=full + ProtectHome=yes +-WatchdogSec=1min ++WatchdogSec=3min + + [Install] + WantedBy=sysinit.target diff --git a/SOURCES/0364-core-bump-net.unix.max_dgram_qlen-really-early-durin.patch b/SOURCES/0364-core-bump-net.unix.max_dgram_qlen-really-early-durin.patch new file mode 100644 index 0000000..4a0081b --- /dev/null +++ b/SOURCES/0364-core-bump-net.unix.max_dgram_qlen-really-early-durin.patch @@ -0,0 +1,90 @@ +From a3b8feb9320f745f960fe8f7006183137f4969b1 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Nov 2015 09:34:05 +0100 +Subject: [PATCH] core: bump net.unix.max_dgram_qlen really early during boot + +Only that way it actually has an effect on all our sockets, including +$NOTIFY_SOCKET. + +(cherry picked from commit 19854865a877a3a4fa3d04550c15a99c0e1187ff) +Related: #1267707 +--- + src/core/main.c | 36 ++++++++++++++++++++++++++++++++++++ + src/shared/def.h | 3 +++ + 2 files changed, 39 insertions(+) + +diff --git a/src/core/main.c b/src/core/main.c +index 60ea36c..c9d8ce4 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1198,6 +1198,7 @@ static int status_welcome(void) { + + static int write_container_id(void) { + const char *c; ++ int r; + + c = getenv("container"); + if (isempty(c)) +@@ -1206,6 +1207,40 @@ static int write_container_id(void) { + return write_string_file("/run/systemd/container", c); + } + ++static int bump_unix_max_dgram_qlen(void) { ++ _cleanup_free_ char *qlen = NULL; ++ unsigned long v; ++ int r; ++ ++ /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel ++ * default of 16 is simply too low. We set the value really ++ * really early during boot, so that it is actually applied to ++ * all our sockets, including the $NOTIFY_SOCKET one. */ ++ ++ r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m"); ++ ++ r = safe_atolu(qlen, &v); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m"); ++ ++ if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN) ++ return 0; ++ ++ free(qlen); ++ qlen = NULL; ++ if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0) ++ return log_oom(); ++ ++ r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen); ++ if (r < 0) ++ return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, ++ "Failed to bump AF_UNIX datagram queue length, ignoring: %m"); ++ ++ return 1; ++} ++ + int main(int argc, char *argv[]) { + Manager *m = NULL; + int r, retval = EXIT_FAILURE; +@@ -1571,6 +1606,7 @@ int main(int argc, char *argv[]) { + hostname_setup(); + machine_id_setup(NULL); + loopback_setup(); ++ bump_unix_max_dgram_qlen(); + + test_mtab(); + test_usr(); +diff --git a/src/shared/def.h b/src/shared/def.h +index a3d9fcf..76daf01 100644 +--- a/src/shared/def.h ++++ b/src/shared/def.h +@@ -35,6 +35,9 @@ + * the watchdog pings will keep the loop busy. */ + #define DEFAULT_EXIT_USEC (30*USEC_PER_SEC) + ++/* The default value for the net.unix.max_dgram_qlen sysctl */ ++#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL ++ + #define SYSTEMD_CGROUP_CONTROLLER "name=systemd" + + #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT diff --git a/SOURCES/0365-core-fix-priority-ordering-in-notify-handling.patch b/SOURCES/0365-core-fix-priority-ordering-in-notify-handling.patch new file mode 100644 index 0000000..bc8efb1 --- /dev/null +++ b/SOURCES/0365-core-fix-priority-ordering-in-notify-handling.patch @@ -0,0 +1,228 @@ +From 64e21697bdefe0a37edc8557fd110daea2667771 Mon Sep 17 00:00:00 2001 +From: David Herrmann +Date: Wed, 28 Oct 2015 19:11:36 +0100 +Subject: [PATCH] core: fix priority ordering in notify-handling + +Currently, we dispatch NOTIFY messages in a tight loop. Regardless how +much data is incoming, we always dispatch everything that is queued. +This, however, completely breaks priority event-handling of sd-event. +When dispatching one NOTIFY event, another completely different event +might fire, or might be queued by the NOTIFY handling. However, this +event will not get dispatched until all other further NOTIFY messages are +handled. Those might even arrive _after_ the other event fired, and as +such completely break priority ordering of sd-event (which several code +paths rely on). + +Break this by never dispatching multiple messages. Just return after each +message that was read and let sd-event handle everything else. + +(The patch looks scarier that it is. It basically just drops the for(;;) + loop and re-indents the loop-content.) + +(cherry picked from commit b215b0ede11c0dda90009c8412609d2416150075) +Related: #1267707 +--- + src/core/manager.c | 158 ++++++++++++++++++++++++++--------------------------- + 1 file changed, 78 insertions(+), 80 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 5da8365..c502199 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1635,9 +1635,33 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char * + } + + static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { ++ _cleanup_fdset_free_ FDSet *fds = NULL; + Manager *m = userdata; ++ ++ char buf[NOTIFY_BUFFER_MAX+1]; ++ struct iovec iovec = { ++ .iov_base = buf, ++ .iov_len = sizeof(buf)-1, ++ }; ++ union { ++ struct cmsghdr cmsghdr; ++ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + ++ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; ++ } control = {}; ++ struct msghdr msghdr = { ++ .msg_iov = &iovec, ++ .msg_iovlen = 1, ++ .msg_control = &control, ++ .msg_controllen = sizeof(control), ++ }; ++ ++ struct cmsghdr *cmsg; ++ struct ucred *ucred = NULL; ++ bool found = false; ++ Unit *u1, *u2, *u3; ++ int r, *fd_array = NULL; ++ unsigned n_fds = 0; + ssize_t n; +- int r; + + assert(m); + assert(m->notify_fd == fd); +@@ -1647,108 +1671,82 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + return 0; + } + +- for (;;) { +- _cleanup_fdset_free_ FDSet *fds = NULL; +- char buf[NOTIFY_BUFFER_MAX+1]; +- struct iovec iovec = { +- .iov_base = buf, +- .iov_len = sizeof(buf)-1, +- }; +- union { +- struct cmsghdr cmsghdr; +- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + +- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; +- } control = {}; +- struct msghdr msghdr = { +- .msg_iov = &iovec, +- .msg_iovlen = 1, +- .msg_control = &control, +- .msg_controllen = sizeof(control), +- }; +- struct cmsghdr *cmsg; +- struct ucred *ucred = NULL; +- bool found = false; +- Unit *u1, *u2, *u3; +- int *fd_array = NULL; +- unsigned n_fds = 0; +- +- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); +- if (n < 0) { +- if (errno == EAGAIN || errno == EINTR) +- break; ++ n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); ++ if (n < 0) { ++ if (errno == EAGAIN || errno == EINTR) ++ return 0; + +- return -errno; +- } ++ return -errno; ++ } + +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { +- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { ++ for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { ++ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + +- fd_array = (int*) CMSG_DATA(cmsg); +- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); ++ fd_array = (int*) CMSG_DATA(cmsg); ++ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + +- } else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_CREDENTIALS && +- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { ++ } else if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_CREDENTIALS && ++ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + +- ucred = (struct ucred*) CMSG_DATA(cmsg); +- } ++ ucred = (struct ucred*) CMSG_DATA(cmsg); + } ++ } + +- if (n_fds > 0) { +- assert(fd_array); ++ if (n_fds > 0) { ++ assert(fd_array); + +- r = fdset_new_array(&fds, fd_array, n_fds); +- if (r < 0) { +- close_many(fd_array, n_fds); +- return log_oom(); +- } ++ r = fdset_new_array(&fds, fd_array, n_fds); ++ if (r < 0) { ++ close_many(fd_array, n_fds); ++ return log_oom(); + } ++ } + +- if (!ucred || ucred->pid <= 0) { +- log_warning("Received notify message without valid credentials. Ignoring."); +- continue; +- } ++ if (!ucred || ucred->pid <= 0) { ++ log_warning("Received notify message without valid credentials. Ignoring."); ++ return 0; ++ } + +- if ((size_t) n >= sizeof(buf)) { +- log_warning("Received notify message exceeded maximum size. Ignoring."); +- continue; +- } ++ if ((size_t) n >= sizeof(buf)) { ++ log_warning("Received notify message exceeded maximum size. Ignoring."); ++ return 0; ++ } + +- buf[n] = 0; ++ buf[n] = 0; + +- /* Notify every unit that might be interested, but try +- * to avoid notifying the same one multiple times. */ +- u1 = manager_get_unit_by_pid(m, ucred->pid); +- if (u1) { +- manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); +- found = true; +- } ++ /* Notify every unit that might be interested, but try ++ * to avoid notifying the same one multiple times. */ ++ u1 = manager_get_unit_by_pid(m, ucred->pid); ++ if (u1) { ++ manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); ++ found = true; ++ } + +- u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); +- if (u2 && u2 != u1) { +- manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); +- found = true; +- } ++ u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); ++ if (u2 && u2 != u1) { ++ manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); ++ found = true; ++ } + +- u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); +- if (u3 && u3 != u2 && u3 != u1) { +- manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); +- found = true; +- } ++ u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); ++ if (u3 && u3 != u2 && u3 != u1) { ++ manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); ++ found = true; ++ } + +- if (!found) +- log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); ++ if (!found) ++ log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); + +- if (fdset_size(fds) > 0) +- log_warning("Got auxiliary fds with notification message, closing all."); +- } ++ if (fdset_size(fds) > 0) ++ log_warning("Got auxiliary fds with notification message, closing all."); + + return 0; + } + + static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { + uint64_t iteration; +- ++ + assert(m); + assert(u); + assert(si); diff --git a/SOURCES/0366-tests-fix-personality-tests-on-ppc64-and-aarch64.patch b/SOURCES/0366-tests-fix-personality-tests-on-ppc64-and-aarch64.patch new file mode 100644 index 0000000..96ae2f1 --- /dev/null +++ b/SOURCES/0366-tests-fix-personality-tests-on-ppc64-and-aarch64.patch @@ -0,0 +1,85 @@ +From 89a7c7e55af18c4f18c0d83c244dbe20ddb85515 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 29 Jul 2016 15:03:02 +0200 +Subject: [PATCH] tests: fix personality tests on ppc64 and aarch64 + +Resolves: #1361049 +--- + src/shared/util.c | 16 ++++++++++++++++ + src/test/test-execute.c | 6 ++++++ + test/exec-personality-aarch64.service | 7 +++++++ + test/exec-personality-ppc64.service | 7 +++++++ + 4 files changed, 36 insertions(+) + create mode 100644 test/exec-personality-aarch64.service + create mode 100644 test/exec-personality-ppc64.service + +diff --git a/src/shared/util.c b/src/shared/util.c +index f75ed9d..3030261 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -6986,6 +6986,22 @@ unsigned long personality_from_string(const char *p) { + + if (streq(p, "s390")) + return PER_LINUX; ++ ++#elif defined(__powerpc64__) ++ ++# if defined(__BIG_ENDIAN__) ++ if (streq(p, "ppc64")) ++ return PER_LINUX; ++# else ++ if (streq(p, "ppc64le")) ++ return PER_LINUX; ++# endif ++ ++#elif defined(__aarch64__) ++ ++ if (streq(p, "aarch64")) ++ return PER_LINUX; ++ + #endif + + /* personality(7) documents that 0xffffffffUL is used for +diff --git a/src/test/test-execute.c b/src/test/test-execute.c +index 38522a1..5a02960 100644 +--- a/src/test/test-execute.c ++++ b/src/test/test-execute.c +@@ -83,6 +83,12 @@ static void test_exec_personality(Manager *m) { + #elif defined(__s390__) + test(m, "exec-personality-s390.service", 0, CLD_EXITED); + ++#elif defined(__powerpc64__) ++ test(m, "exec-personality-ppc64.service", 0, CLD_EXITED); ++ ++#elif defined(__aarch64__) ++ test(m, "exec-personality-aarch64.service", 0, CLD_EXITED); ++ + #else + test(m, "exec-personality-x86.service", 0, CLD_EXITED); + #endif +diff --git a/test/exec-personality-aarch64.service b/test/exec-personality-aarch64.service +new file mode 100644 +index 0000000..8511174 +--- /dev/null ++++ b/test/exec-personality-aarch64.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for Personality=aarch64 ++ ++[Service] ++ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "aarch64")' ++Type=oneshot ++Personality=aarch64 +diff --git a/test/exec-personality-ppc64.service b/test/exec-personality-ppc64.service +new file mode 100644 +index 0000000..4432074 +--- /dev/null ++++ b/test/exec-personality-ppc64.service +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Test for Personality=ppc64 ++ ++[Service] ++ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "ppc64" -o $(uname -m) = "ppc64le")' ++Type=oneshot ++Personality=ppc64 diff --git a/SOURCES/0367-systemctl-consider-service-running-only-when-it-is-i.patch b/SOURCES/0367-systemctl-consider-service-running-only-when-it-is-i.patch new file mode 100644 index 0000000..2197d54 --- /dev/null +++ b/SOURCES/0367-systemctl-consider-service-running-only-when-it-is-i.patch @@ -0,0 +1,29 @@ +From 94fec84897ab40bf2bc92f0d395a93ecac1b45be Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Wed, 3 Aug 2016 17:08:37 +0200 +Subject: [PATCH] systemctl: consider service running only when it is in active + or reloading state (#3874) + +Otherwise for example services that are failing on start and have Restart=on-failure +and bigger RestartSec systemctl status will return 0. + +Fixes: #3864 +Cherry-picked from: 7f5da8bd4fb1ba49ba40195a74ca76bb5d4d1f81 +Resolves: #1362461 +--- + src/systemctl/systemctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 93b7a19..b7496c0 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -4339,7 +4339,7 @@ static int show_one( + else if (streq(verb, "status")) { + print_status_info(&info, ellipsized); + +- if (info.active_state && STR_IN_SET(info.active_state, "inactive", "failed")) ++ if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading")) + r = EXIT_PROGRAM_NOT_RUNNING; + else + r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK; diff --git a/SOURCES/0368-install-do-not-crash-when-processing-empty-masked-un.patch b/SOURCES/0368-install-do-not-crash-when-processing-empty-masked-un.patch new file mode 100644 index 0000000..874819d --- /dev/null +++ b/SOURCES/0368-install-do-not-crash-when-processing-empty-masked-un.patch @@ -0,0 +1,24 @@ +From 7d6f53ece9b0a397ee2f8bdaa1a52ef2f03bd81f Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 9 Aug 2016 13:02:37 +0200 +Subject: [PATCH] install: do not crash when processing empty (masked) unit + file + +Related: #1159308 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index f190dbf..f7f9866 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -996,7 +996,7 @@ static int unit_file_load( + if (fstat(fd, &st) < 0) + return -errno; + if (null_or_empty(&st)) { +- info->type = UNIT_FILE_MASKED; ++ info->type = UNIT_FILE_TYPE_MASKED; + return 0; + } + if (S_ISDIR(st.st_mode)) diff --git a/SOURCES/0369-Revert-install-fix-disable-via-unit-file-path.patch b/SOURCES/0369-Revert-install-fix-disable-via-unit-file-path.patch new file mode 100644 index 0000000..0cb195e --- /dev/null +++ b/SOURCES/0369-Revert-install-fix-disable-via-unit-file-path.patch @@ -0,0 +1,32 @@ +From f79f65a2957cca23e0347eb2c9dfbd53be5c8dba Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 8 Aug 2016 15:15:14 +0200 +Subject: [PATCH] Revert "install: fix disable via unit file path" + +This reverts commit 96df052a6a9d09cde2d437861727bf37fe6446b4. + +Related: #1348208 +--- + src/shared/install.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index f7f9866..9962508 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1910,12 +1910,10 @@ int unit_file_disable( + return r; + + STRV_FOREACH(i, files) { ++ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) ++ return -EINVAL; + +- if (!is_path(*i)) +- r = install_info_add(&c, *i, NULL, NULL); +- else +- r = install_info_add(&c, NULL, *i, NULL); +- ++ r = install_info_add(&c, *i, NULL, NULL); + if (r < 0) + return r; + } diff --git a/SOURCES/0370-systemctl-allow-disable-on-the-unit-file-path-but-wa.patch b/SOURCES/0370-systemctl-allow-disable-on-the-unit-file-path-but-wa.patch new file mode 100644 index 0000000..03a19ba --- /dev/null +++ b/SOURCES/0370-systemctl-allow-disable-on-the-unit-file-path-but-wa.patch @@ -0,0 +1,82 @@ +From 1f8b1e35e3ec80c50201403171b7375ff14c808c Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 26 Jul 2016 14:25:52 +0200 +Subject: [PATCH] systemctl: allow disable on the unit file path, but warn + about it (#3806) + +systemd now returns an error when it is asked to perform disable on the +unit file path. In the past this was allowed, but systemd never really +considered an actual content of the [Install] section of the unit +file. Instead it performed disable on the unit name, i.e. purged all +symlinks pointing to the given unit file (undo of implicit link action +done by systemd when enable is called on the unit file path) and all +symlinks that have the same basename as the given unit file. + +However, to notice that [Install] info of the file is not consulted one +must create additional symlinks manually. I argue that in most cases +users do not create such links. Let's be nice to our users and don't +break existing scripts that expect disable to work with the unit file +path. + +Fixes #3706. + +IMPORTANT +========= +Note that in this downstream backport we actually pass false to +normalize_names(), hence it will not produce any warning when full path +is passed in. This is because we need to preserve behavior compatible +with prior systemd versions shipped in RHEL. + +Cherry-picked from: 1d3c86c06fca8311923fcf81af0ab0bbb66e1edd +Resolves: #1348208 +--- + src/systemctl/systemctl.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index b7496c0..5899818 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -5333,6 +5333,29 @@ static int mangle_names(char **original_names, char ***mangled_names) { + return 0; + } + ++static int normalize_names(char **names, bool warn_if_path) { ++ char **u; ++ bool was_path = false; ++ ++ STRV_FOREACH(u, names) { ++ int r; ++ ++ if (!is_path(*u)) ++ continue; ++ ++ r = free_and_strdup(u, basename(*u)); ++ if (r < 0) ++ return log_error_errno(r, "Failed to normalize unit file path: %m"); ++ ++ was_path = true; ++ } ++ ++ if (warn_if_path && was_path) ++ log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name."); ++ ++ return 0; ++} ++ + static int enable_unit(sd_bus *bus, char **args) { + _cleanup_strv_free_ char **names = NULL; + const char *verb = args[0]; +@@ -5357,6 +5380,12 @@ static int enable_unit(sd_bus *bus, char **args) { + if (strv_isempty(names)) + return 0; + ++ if (streq(verb, "disable")) { ++ r = normalize_names(names, false); ++ if (r < 0) ++ return r; ++ } ++ + if (!bus || avoid_bus()) { + if (streq(verb, "enable")) { + r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); diff --git a/SOURCES/0371-tmpfiles-enforce-ordering-when-executing-lines.patch b/SOURCES/0371-tmpfiles-enforce-ordering-when-executing-lines.patch new file mode 100644 index 0000000..193b35c --- /dev/null +++ b/SOURCES/0371-tmpfiles-enforce-ordering-when-executing-lines.patch @@ -0,0 +1,102 @@ +From fd09d69b1bca2b4b602f4ee98d4749a39af04bb4 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 10 Apr 2015 16:22:22 +0200 +Subject: [PATCH] tmpfiles: enforce ordering when executing lines + +Always create files first, and then adjust their ACLs, xattrs, file +attributes, never the opposite. Previously the order was not +deterministic, thus possibly first adjusting ACLs/xattrs/file +attributes before actually creating the items. + +Cherry-picked from: 17493fa5d17cadce3b773692d3eeab137de7d323 +Resolves: #1365870 +--- + src/tmpfiles/tmpfiles.c | 39 +++++++++++++++++++++++++++++++++++---- + 1 file changed, 35 insertions(+), 4 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 64c733a..bda89df 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -78,18 +78,18 @@ typedef enum ItemType { + COPY_FILES = 'C', + + /* These ones take globs */ ++ WRITE_FILE = 'w', + SET_XATTR = 't', + RECURSIVE_SET_XATTR = 'T', + SET_ACL = 'a', + RECURSIVE_SET_ACL = 'A', +- WRITE_FILE = 'w', + IGNORE_PATH = 'x', + IGNORE_DIRECTORY_PATH = 'X', + REMOVE_PATH = 'r', + RECURSIVE_REMOVE_PATH = 'R', +- ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */ + RELABEL_PATH = 'z', + RECURSIVE_RELABEL_PATH = 'Z', ++ ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */ + } ItemType; + + typedef struct Item { +@@ -1480,6 +1480,31 @@ static void item_array_free(ItemArray *a) { + free(a); + } + ++static int item_compare(const void *a, const void *b) { ++ const Item *x = a, *y = b; ++ ++ /* Make sure that the ownership taking item is put first, so ++ * that we first create the node, and then can adjust it */ ++ ++ if (takes_ownership(x->type) && !takes_ownership(y->type)) ++ return -1; ++ if (!takes_ownership(x->type) && takes_ownership(y->type)) ++ return 1; ++ ++ return (int) x->type - (int) y->type; ++} ++ ++static void item_array_sort(ItemArray *a) { ++ ++ /* Sort an item array, to enforce stable ordering in which we ++ * apply things. */ ++ ++ if (a->count <= 1) ++ return; ++ ++ qsort(a->items, a->count, sizeof(Item), item_compare); ++} ++ + static bool item_compatible(Item *a, Item *b) { + assert(a); + assert(b); +@@ -1806,6 +1831,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + return log_oom(); + + memcpy(existing->items + existing->count++, &i, sizeof(i)); ++ item_array_sort(existing); ++ + zero(i); + return 0; + } +@@ -2045,13 +2072,17 @@ int main(int argc, char *argv[]) { + } + } + +- HASHMAP_FOREACH(a, globs, iterator) { ++ /* The non-globbing ones usually create things, hence we apply ++ * them first */ ++ HASHMAP_FOREACH(a, items, iterator) { + k = process_item_array(a); + if (k < 0 && r == 0) + r = k; + } + +- HASHMAP_FOREACH(a, items, iterator) { ++ /* The globbing ones usually alter things, hence we apply them ++ * second. */ ++ HASHMAP_FOREACH(a, globs, iterator) { + k = process_item_array(a); + if (k < 0 && r == 0) + r = k; diff --git a/SOURCES/0372-Introduce-bus_unit_check_load_state-helper.patch b/SOURCES/0372-Introduce-bus_unit_check_load_state-helper.patch new file mode 100644 index 0000000..ed25b0f --- /dev/null +++ b/SOURCES/0372-Introduce-bus_unit_check_load_state-helper.patch @@ -0,0 +1,53 @@ +From c55a7f9448378c10a7e8074db908502ae5ff60aa Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Fri, 13 Nov 2015 14:12:19 +0100 +Subject: [PATCH] Introduce bus_unit_check_load_state() helper + +This function is used to check that a previous unit load succeed and +returns 0 in this case. + +In the case the load failed, the function setup a bus error +accordingly and returns -errno. + +(cherry picked from commit 000a996dc46c187f803b67b0b0d51ad4d0bc1658) +Related: #1256858 +--- + src/core/dbus-unit.c | 17 +++++++++++++++++ + src/core/dbus-unit.h | 2 ++ + 2 files changed, 19 insertions(+) + +diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c +index 49770bf..c3654db 100644 +--- a/src/core/dbus-unit.c ++++ b/src/core/dbus-unit.c +@@ -1083,3 +1083,20 @@ int bus_unit_set_properties( + + return n; + } ++ ++int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { ++ ++ if (u->load_state == UNIT_LOADED) ++ return 0; ++ ++ /* Give a better description of the unit error when ++ * possible. Note that in the case of UNIT_MASKED, load_error ++ * is not set. */ ++ if (u->load_state == UNIT_MASKED) ++ return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit is masked."); ++ ++ if (u->load_state == UNIT_NOT_FOUND) ++ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit not found."); ++ ++ return sd_bus_error_set_errnof(error, u->load_error, "Unit is not loaded properly: %m."); ++} +diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h +index 57a5e19..4338496 100644 +--- a/src/core/dbus-unit.h ++++ b/src/core/dbus-unit.h +@@ -37,3 +37,5 @@ int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *use + int bus_unit_queue_job(sd_bus *bus, sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error); + int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error); + int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); ++ ++int bus_unit_check_load_state(Unit *u, sd_bus_error *error); diff --git a/SOURCES/0373-core-use-bus_unit_check_load_state-in-transaction_ad.patch b/SOURCES/0373-core-use-bus_unit_check_load_state-in-transaction_ad.patch new file mode 100644 index 0000000..3962654 --- /dev/null +++ b/SOURCES/0373-core-use-bus_unit_check_load_state-in-transaction_ad.patch @@ -0,0 +1,76 @@ +From a47b58110f92415fcb69441031e4d04fec48b852 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Wed, 2 Dec 2015 17:03:28 +0100 +Subject: [PATCH] core: use bus_unit_check_load_state() in + transaction_add_job_and_dependencies() + +(cherry picked from commit ee87525c5eeacf3ce8fb730bcd3658e8da085046) +Related: #1256858 +--- + src/core/transaction.c | 27 +++++---------------------- + src/systemctl/systemctl.c | 5 +++++ + 2 files changed, 10 insertions(+), 22 deletions(-) + +diff --git a/src/core/transaction.c b/src/core/transaction.c +index aed64fa..57e9cb3 100644 +--- a/src/core/transaction.c ++++ b/src/core/transaction.c +@@ -26,6 +26,7 @@ + #include "bus-util.h" + #include "bus-error.h" + #include "transaction.h" ++#include "dbus-unit.h" + + static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); + +@@ -857,30 +858,12 @@ int transaction_add_job_and_dependencies( + return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, + "Unit %s is not loaded properly.", unit->id); + +- if (type != JOB_STOP && unit->load_state == UNIT_ERROR) { +- if (unit->load_error == -ENOENT || unit->manager->test_run) +- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, +- "Unit %s failed to load: %s.", +- unit->id, +- strerror(-unit->load_error)); +- else +- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, +- "Unit %s failed to load: %s. " +- "See system logs and 'systemctl status %s' for details.", +- unit->id, +- strerror(-unit->load_error), +- unit->id); ++ if (type != JOB_STOP) { ++ r = bus_unit_check_load_state(unit, e); ++ if (r < 0) ++ return r; + } + +- if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) +- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, +- "Unit %s failed to load: %s.", +- unit->id, strerror(-unit->load_error)); +- +- if (type != JOB_STOP && unit->load_state == UNIT_MASKED) +- return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED, +- "Unit %s is masked.", unit->id); +- + if (!unit_job_is_applicable(unit, type)) + return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, + "Job type %s is not applicable for unit %s.", +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 5899818..e4b404a 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -2617,6 +2617,11 @@ static int start_unit_one( + verb = method_to_verb(method); + + log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r)); ++ ++ if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) && ++ !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED)) ++ log_error("See system logs and 'systemctl status %s' for details.", name); ++ + return r; + } + diff --git a/SOURCES/0374-udev-path_id-correct-segmentation-fault-due-to-missi.patch b/SOURCES/0374-udev-path_id-correct-segmentation-fault-due-to-missi.patch new file mode 100644 index 0000000..a0b2982 --- /dev/null +++ b/SOURCES/0374-udev-path_id-correct-segmentation-fault-due-to-missi.patch @@ -0,0 +1,31 @@ +From fb9a50a0ad64f28c00c7d0bbc4ee8908d4233593 Mon Sep 17 00:00:00 2001 +From: Hendrik Brueckner +Date: Fri, 19 Feb 2016 15:21:18 +0100 +Subject: [PATCH] udev/path_id: correct segmentation fault due to missing NULL + check + +Running "udevadm test-builtin path_id /sys/devices/platform/" results +in a segmentation fault. + +The problem is that udev_device_get_subsystem(dev) might return NULL +in a streq() call. Solve this problem by using streq_ptr() instead. + +Cherry-picked from: 5181ab917d6407cb57043e98955f0de1614366ea +Resolves: #1365556 +--- + src/udev/udev-builtin-path_id.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 8359e23..a3b019b 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -729,7 +729,7 @@ restart: + * devices do not expose their buses and do not provide a unique + * and predictable name that way. + */ +- if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport) { ++ if (streq_ptr(udev_device_get_subsystem(dev), "block") && !supported_transport) { + free(path); + path = NULL; + } diff --git a/SOURCES/0375-rules-load-sg-driver-also-when-scsi_target-appears-4.patch b/SOURCES/0375-rules-load-sg-driver-also-when-scsi_target-appears-4.patch new file mode 100644 index 0000000..8b12005 --- /dev/null +++ b/SOURCES/0375-rules-load-sg-driver-also-when-scsi_target-appears-4.patch @@ -0,0 +1,22 @@ +From 3724d66bec53bf53e5378269e6ddf68c99da7f0c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Thu, 18 Aug 2016 14:51:19 +0200 +Subject: [PATCH] rules: load sg driver also when scsi_target appears (#45) + +Resolves: #1322773 +--- + rules/40-redhat.rules | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 9a48add..3335fe5 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -11,6 +11,7 @@ ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/sys + + # load SCSI generic (sg) driver + SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST!="[module/sg]", RUN+="/sbin/modprobe -bv sg" ++SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_target", TEST!="[module/sg]", RUN+="/sbin/modprobe -bv sg" + + # Rule for prandom character device node permissions + KERNEL=="prandom", MODE="0644" diff --git a/SOURCES/0376-fix-gcc-warnings-about-uninitialized-variables.patch b/SOURCES/0376-fix-gcc-warnings-about-uninitialized-variables.patch new file mode 100644 index 0000000..d7e92ab --- /dev/null +++ b/SOURCES/0376-fix-gcc-warnings-about-uninitialized-variables.patch @@ -0,0 +1,483 @@ +From c815acfb5863d9562a3f1e9cbd6204da3364860c Mon Sep 17 00:00:00 2001 +From: Harald Hoyer +Date: Fri, 27 Mar 2015 12:02:49 +0100 +Subject: [PATCH] fix gcc warnings about uninitialized variables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +like: + +src/shared/install.c: In function ‘unit_file_lookup_state’: +src/shared/install.c:1861:16: warning: ‘r’ may be used uninitialized in +this function [-Wmaybe-uninitialized] + return r < 0 ? r : state; + ^ +src/shared/install.c:1796:13: note: ‘r’ was declared here + int r; + ^ + +Conflicts: + src/journal/journal-file.c + src/shared/btrfs-util.c + src/shared/install.c + +Cherry-picked from: a7f7d1bde43fc825c49afea3f946f5b4b3d563e0 +Related: #1318994 +--- + src/import/import-job.c | 2 +- + src/journal-remote/journal-gatewayd.c | 2 +- + src/journal-remote/journal-remote-parse.c | 2 +- + src/journal-remote/journal-remote.c | 4 ++-- + src/journal/catalog.c | 2 +- + src/journal/coredump.c | 4 ++-- + src/journal/journal-file.c | 6 +++--- + src/journal/journal-vacuum.c | 2 +- + src/journal/journalctl.c | 2 +- + src/journal/test-journal-stream.c | 2 +- + src/libsystemd-network/lldp-tlv.c | 8 ++++---- + src/libsystemd-network/sd-dhcp-server.c | 2 +- + src/libsystemd-network/sd-pppoe.c | 2 +- + src/libsystemd/sd-login/sd-login.c | 2 +- + src/network/networkctl.c | 2 +- + src/resolve/resolved-dns-transaction.c | 2 +- + src/resolve/test-dns-domain.c | 2 +- + src/shared/base-filesystem.c | 2 +- + src/shared/capability.c | 2 +- + src/shared/copy.c | 6 +++--- + src/shared/install.c | 2 +- + src/shared/logs-show.c | 2 +- + src/shared/util.c | 4 ++-- + src/test/test-path.c | 2 +- + src/test/test-pty.c | 2 +- + src/udev/net/link-config.c | 2 +- + 26 files changed, 36 insertions(+), 36 deletions(-) + +diff --git a/src/import/import-job.c b/src/import/import-job.c +index 5f9cfd3..d826f49 100644 +--- a/src/import/import-job.c ++++ b/src/import/import-job.c +@@ -80,7 +80,7 @@ void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { + long status; + int r; + +- if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, &j) != CURLE_OK) ++ if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&j) != CURLE_OK) + return; + + if (!j || j->state == IMPORT_JOB_DONE || j->state == IMPORT_JOB_FAILED) +diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c +index 576f7ca..d1f0ce3 100644 +--- a/src/journal-remote/journal-gatewayd.c ++++ b/src/journal-remote/journal-gatewayd.c +@@ -736,7 +736,7 @@ static int request_handler_machine( + RequestMeta *m = connection_cls; + int r; + _cleanup_free_ char* hostname = NULL, *os_name = NULL; +- uint64_t cutoff_from = 0, cutoff_to = 0, usage; ++ uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0; + char *json; + sd_id128_t mid, bid; + _cleanup_free_ char *v = NULL; +diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c +index 7e62954..64089da 100644 +--- a/src/journal-remote/journal-remote-parse.c ++++ b/src/journal-remote/journal-remote-parse.c +@@ -316,7 +316,7 @@ int process_data(RemoteSource *source) { + switch(source->state) { + case STATE_LINE: { + char *line, *sep; +- size_t n; ++ size_t n = 0; + + assert(source->data_size == 0); + +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index 9c515f9..4fac55c 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -353,7 +353,7 @@ static int remove_source(RemoteServer *s, int fd) { + + static int add_source(RemoteServer *s, int fd, char* name, bool own_name) { + +- RemoteSource *source; ++ RemoteSource *source = NULL; + int r; + + /* This takes ownership of name, even on failure, if own_name is true. */ +@@ -1148,7 +1148,7 @@ static int dispatch_raw_connection_event(sd_event_source *event, + .size = sizeof(union sockaddr_union), + .type = SOCK_STREAM, + }; +- char *hostname; ++ char *hostname = NULL; + + fd2 = accept_connection("raw", fd, &addr, &hostname); + if (fd2 < 0) +diff --git a/src/journal/catalog.c b/src/journal/catalog.c +index f170232..a9c40c6 100644 +--- a/src/journal/catalog.c ++++ b/src/journal/catalog.c +@@ -559,7 +559,7 @@ static const char *find_id(void *p, sd_id128_t id) { + int catalog_get(const char* database, sd_id128_t id, char **_text) { + _cleanup_close_ int fd = -1; + void *p = NULL; +- struct stat st; ++ struct stat st = {}; + char *text = NULL; + int r; + const char *s; +diff --git a/src/journal/coredump.c b/src/journal/coredump.c +index f7ba019..59ccd46 100644 +--- a/src/journal/coredump.c ++++ b/src/journal/coredump.c +@@ -244,7 +244,7 @@ static int maybe_remove_external_coredump(const char *filename, off_t size) { + + static int make_filename(const char *info[_INFO_LEN], char **ret) { + _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL; +- sd_id128_t boot; ++ sd_id128_t boot = {}; + int r; + + assert(info); +@@ -843,7 +843,7 @@ log: + /* Optionally store the entire coredump in the journal */ + if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) && + coredump_size <= (off_t) arg_journal_size_max) { +- size_t sz; ++ size_t sz = 0; + + /* Store the coredump itself in the journal */ + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index ef18497..2a93460 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -911,7 +911,7 @@ int journal_file_find_data_object_with_hash( + if (o->object.flags & OBJECT_COMPRESSION_MASK) { + #if defined(HAVE_XZ) || defined(HAVE_LZ4) + uint64_t l; +- size_t rsize; ++ size_t rsize = 0; + + l = le64toh(o->object.size); + if (l <= offsetof(Object, data.payload)) +@@ -1075,7 +1075,7 @@ static int journal_file_append_data( + + #if defined(HAVE_XZ) || defined(HAVE_LZ4) + if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) { +- size_t rsize; ++ size_t rsize = 0; + + compression = compress_blob(data, size, o->data.payload, &rsize); + +@@ -2903,7 +2903,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 + + if (o->object.flags & OBJECT_COMPRESSION_MASK) { + #if defined(HAVE_XZ) || defined(HAVE_LZ4) +- size_t rsize; ++ size_t rsize = 0; + + r = decompress_blob(o->object.flags & OBJECT_COMPRESSION_MASK, + o->data.payload, l, &from->compress_buffer, &from->compress_buffer_size, &rsize, 0); +diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c +index 832c327..856d11e 100644 +--- a/src/journal/journal-vacuum.c ++++ b/src/journal/journal-vacuum.c +@@ -76,7 +76,7 @@ static void patch_realtime( + unsigned long long *realtime) { + + _cleanup_free_ const char *path = NULL; +- usec_t x, crtime; ++ usec_t x, crtime = 0; + + /* The timestamp was determined by the file name, but let's + * see if the file might actually be older than the file name +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index a38ce4b..6ba8847 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1644,7 +1644,7 @@ static int verify(sd_journal *j) { + + ORDERED_HASHMAP_FOREACH(f, j->files, i) { + int k; +- usec_t first, validated, last; ++ usec_t first = 0, validated = 0, last = 0; + + #ifdef HAVE_GCRYPT + if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) +diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c +index 3996e77..b8caeb3 100644 +--- a/src/journal/test-journal-stream.c ++++ b/src/journal/test-journal-stream.c +@@ -42,7 +42,7 @@ static void verify_contents(sd_journal *j, unsigned skip) { + const void *d; + char *k, *c; + size_t l; +- unsigned u; ++ unsigned u = 0; + + assert_se(sd_journal_get_cursor(j, &k) >= 0); + printf("cursor: %s\n", k); +diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c +index e43d70d..e32783f 100644 +--- a/src/libsystemd-network/lldp-tlv.c ++++ b/src/libsystemd-network/lldp-tlv.c +@@ -156,7 +156,7 @@ static inline int tlv_packet_read_internal(tlv_section *m, void **data) { + } + + int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) { +- void *val; ++ void *val = NULL; + int r; + + assert_return(m, -EINVAL); +@@ -174,7 +174,7 @@ int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) { + + int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) { + uint16_t t; +- void *val; ++ void *val = NULL; + int r; + + assert_return(m, -EINVAL); +@@ -211,7 +211,7 @@ int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) { + } + + int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { +- void *val; ++ void *val = NULL; + int r; + + assert_return(m, -EINVAL); +@@ -229,7 +229,7 @@ int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { + } + + int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) { +- void *val; ++ void *val = NULL; + int r; + + assert_return(m, -EINVAL); +diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c +index 3f89f34..0f284eb 100644 +--- a/src/libsystemd-network/sd-dhcp-server.c ++++ b/src/libsystemd-network/sd-dhcp-server.c +@@ -776,7 +776,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, + if (pool_offset >= 0 && + server->bound_leases[pool_offset] == existing_lease) { + DHCPLease *lease; +- usec_t time_now; ++ usec_t time_now = 0; + + if (!existing_lease) { + lease = new0(DHCPLease, 1); +diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c +index 4f49b79..83e58a3 100644 +--- a/src/libsystemd-network/sd-pppoe.c ++++ b/src/libsystemd-network/sd-pppoe.c +@@ -340,7 +340,7 @@ static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata); + + static int pppoe_arm_timeout(sd_pppoe *ppp) { + _cleanup_event_source_unref_ sd_event_source *timeout = NULL; +- usec_t next_timeout; ++ usec_t next_timeout = 0; + int r; + + assert(ppp); +diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c +index f71749f..cc0677b 100644 +--- a/src/libsystemd/sd-login/sd-login.c ++++ b/src/libsystemd/sd-login/sd-login.c +@@ -82,7 +82,7 @@ _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { + } + + _public_ int sd_peer_get_session(int fd, char **session) { +- struct ucred ucred; ++ struct ucred ucred = {}; + int r; + + assert_return(fd >= 0, -EINVAL); +diff --git a/src/network/networkctl.c b/src/network/networkctl.c +index aa83f32..778670b 100644 +--- a/src/network/networkctl.c ++++ b/src/network/networkctl.c +@@ -964,7 +964,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { + return -ENOMEM; + + } else if (streq(a, "_TTL")) { +- long long unsigned x; ++ long long unsigned x = 0; + usec_t time; + + r = safe_atollu(b, &x); +diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c +index 74b0634..bc1a90d 100644 +--- a/src/resolve/resolved-dns-transaction.c ++++ b/src/resolve/resolved-dns-transaction.c +@@ -252,7 +252,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { + fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port); + else { + union in_addr_union address; +- int family; ++ int family = AF_UNSPEC; + + /* Otherwise, try to talk to the owner of a + * the IP address, in case this is a reverse +diff --git a/src/resolve/test-dns-domain.c b/src/resolve/test-dns-domain.c +index ebc8d98..4963a9c 100644 +--- a/src/resolve/test-dns-domain.c ++++ b/src/resolve/test-dns-domain.c +@@ -162,7 +162,7 @@ static void test_dns_name_single_label(void) { + + static void test_dns_name_reverse_one(const char *address, const char *name) { + _cleanup_free_ char *p = NULL; +- union in_addr_union a, b; ++ union in_addr_union a, b = {}; + int familya, familyb; + + assert_se(in_addr_from_string_auto(address, &familya, &a) >= 0); +diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c +index 73907c6..20a69bd 100644 +--- a/src/shared/base-filesystem.c ++++ b/src/shared/base-filesystem.c +@@ -55,7 +55,7 @@ static const BaseFilesystem table[] = { + int base_filesystem_create(const char *root) { + _cleanup_close_ int fd = -1; + unsigned i; +- int r; ++ int r = 0; + + fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); + if (fd < 0) +diff --git a/src/shared/capability.c b/src/shared/capability.c +index 915ceb9..2b963fd 100644 +--- a/src/shared/capability.c ++++ b/src/shared/capability.c +@@ -55,7 +55,7 @@ unsigned long cap_last_cap(void) { + static thread_local unsigned long saved; + static thread_local bool valid = false; + _cleanup_free_ char *content = NULL; +- unsigned long p; ++ unsigned long p = 0; + int r; + + if (valid) +diff --git a/src/shared/copy.c b/src/shared/copy.c +index 0239a58..2a0cb28 100644 +--- a/src/shared/copy.c ++++ b/src/shared/copy.c +@@ -360,7 +360,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) { + } + + int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) { +- int fdt, r; ++ int fdt = -1, r; + + assert(from); + assert(to); +@@ -390,7 +390,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned + } + + int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) { +- _cleanup_free_ char *t; ++ _cleanup_free_ char *t = NULL; + int r; + + assert(from); +@@ -415,7 +415,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace + int copy_times(int fdf, int fdt) { + struct timespec ut[2]; + struct stat st; +- usec_t crtime; ++ usec_t crtime = 0; + + assert(fdf >= 0); + assert(fdt >= 0); +diff --git a/src/shared/install.c b/src/shared/install.c +index 9962508..61aaafe 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2046,7 +2046,7 @@ UnitFileState unit_file_lookup_state( + _cleanup_(install_context_done) InstallContext c = {}; + InstallInfo *i; + UnitFileState state; +- int r; ++ int r = 0; + + assert(paths); + assert(name); +diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c +index 8c37411..a572be9 100644 +--- a/src/shared/logs-show.c ++++ b/src/shared/logs-show.c +@@ -993,7 +993,7 @@ static int show_journal(FILE *f, + + if (warn_cutoff && line < how_many && not_before > 0) { + sd_id128_t boot_id; +- usec_t cutoff; ++ usec_t cutoff = 0; + + /* Check whether the cutoff line is too early */ + +diff --git a/src/shared/util.c b/src/shared/util.c +index 3030261..4c441a5 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -3073,7 +3073,7 @@ int getttyname_malloc(int fd, char **ret) { + + int getttyname_harder(int fd, char **r) { + int k; +- char *s; ++ char *s = NULL; + + k = getttyname_malloc(fd, &s); + if (k < 0) +@@ -3627,7 +3627,7 @@ char **replace_env_argv(char **argv, char **env) { + /* If $FOO appears as single word, replace it by the split up variable */ + if ((*i)[0] == '$' && (*i)[1] != '{') { + char *e; +- char **w, **m; ++ char **w, **m = NULL; + unsigned q; + + e = strv_env_get(env, *i+1); +diff --git a/src/test/test-path.c b/src/test/test-path.c +index 4f9f5c1..a3295aa 100644 +--- a/src/test/test-path.c ++++ b/src/test/test-path.c +@@ -33,7 +33,7 @@ static int setup_test(Manager **m) { + char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit", + "directorynotempty", "makedirectory"); + char **test_path; +- Manager *tmp; ++ Manager *tmp = NULL; + int r; + + assert_se(m); +diff --git a/src/test/test-pty.c b/src/test/test-pty.c +index cab569a..67c125a 100644 +--- a/src/test/test-pty.c ++++ b/src/test/test-pty.c +@@ -97,7 +97,7 @@ static void run_parent(Pty *pty) { + + static void test_pty(void) { + pid_t pid; +- Pty *pty; ++ Pty *pty = NULL; + + rcvsiz = 0; + zero(rcvbuf); +diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c +index 489593f..ad6a82e 100644 +--- a/src/udev/net/link-config.c ++++ b/src/udev/net/link-config.c +@@ -474,7 +474,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, + + int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) { + const char *name; +- char *driver; ++ char *driver = NULL; + int r; + + name = udev_device_get_sysname(device); diff --git a/SOURCES/0377-journalctl-rework-code-that-checks-whether-we-have-a.patch b/SOURCES/0377-journalctl-rework-code-that-checks-whether-we-have-a.patch new file mode 100644 index 0000000..f2389ba --- /dev/null +++ b/SOURCES/0377-journalctl-rework-code-that-checks-whether-we-have-a.patch @@ -0,0 +1,339 @@ +From e9bef2f8146ccf152459248775eec8e8ce123865 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 22 Apr 2015 22:54:23 +0200 +Subject: [PATCH] journalctl: rework code that checks whether we have access to + /var/log/journal + +- fix some memory leaks on error conditions + +- handle all error cases properly, and log about failures + +- move HAVE_ACL and no-HAVE_ACL code closer to each other + +Cherry-picked from: e346512c684e9efae84c6442f7e6a5781564ecde +Related: #1318994 +--- + src/journal/journalctl.c | 120 ++++++++++++++++++++++++----------------------- + src/shared/acl-util.c | 102 ++++++++++++++++++++++------------------ + src/shared/acl-util.h | 2 +- + 3 files changed, 119 insertions(+), 105 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 6ba8847..f60e641 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1680,61 +1680,76 @@ static int verify(sd_journal *j) { + return r; + } + +-#ifdef HAVE_ACL + static int access_check_var_log_journal(sd_journal *j) { ++#ifdef HAVE_ACL + _cleanup_strv_free_ char **g = NULL; +- bool have_access; ++ const char* dir; ++#endif + int r; + + assert(j); + +- have_access = in_group("systemd-journal") > 0; ++ if (arg_quiet) ++ return 0; + +- if (!have_access) { +- const char* dir; ++ /* If we are root, we should have access, don't warn. */ ++ if (getuid() == 0) ++ return 0; + +- if (access("/run/log/journal", F_OK) >= 0) +- dir = "/run/log/journal"; +- else +- dir = "/var/log/journal"; ++ /* If we are in the 'systemd-journal' group, we should have ++ * access too. */ ++ r = in_group("systemd-journal"); ++ if (r < 0) ++ return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m"); ++ if (r > 0) ++ return 0; + +- /* Let's enumerate all groups from the default ACL of +- * the directory, which generally should allow access +- * to most journal files too */ +- r = search_acl_groups(&g, dir, &have_access); +- if (r < 0) +- return r; +- } ++#ifdef HAVE_ACL ++ if (laccess("/run/log/journal", F_OK) >= 0) ++ dir = "/run/log/journal"; ++ else ++ dir = "/var/log/journal"; + +- if (!have_access) { ++ /* If we are in any of the groups listed in the journal ACLs, ++ * then all is good, too. Let's enumerate all groups from the ++ * default ACL of the directory, which generally should allow ++ * access to most journal files too. */ ++ r = acl_search_groups(dir, &g); ++ if (r < 0) ++ return log_error_errno(r, "Failed to search journal ACL: %m"); ++ if (r > 0) ++ return 0; + +- if (strv_isempty(g)) +- log_notice("Hint: You are currently not seeing messages from other users and the system.\n" +- " Users in the 'systemd-journal' group can see all messages. Pass -q to\n" +- " turn off this notice."); +- else { +- _cleanup_free_ char *s = NULL; ++ /* Print a pretty list, if there were ACLs set. */ ++ if (!strv_isempty(g)) { ++ _cleanup_free_ char *s = NULL; + +- r = strv_extend(&g, "systemd-journal"); +- if (r < 0) +- return log_oom(); ++ /* Thre are groups in the ACL, let's list them */ ++ r = strv_extend(&g, "systemd-journal"); ++ if (r < 0) ++ return log_oom(); + +- strv_sort(g); +- strv_uniq(g); ++ strv_sort(g); ++ strv_uniq(g); + +- s = strv_join(g, "', '"); +- if (!s) +- return log_oom(); ++ s = strv_join(g, "', '"); ++ if (!s) ++ return log_oom(); + +- log_notice("Hint: You are currently not seeing messages from other users and the system.\n" +- " Users in groups '%s' can see all messages.\n" +- " Pass -q to turn off this notice.", s); +- } ++ log_notice("Hint: You are currently not seeing messages from other users and the system.\n" ++ " Users in groups '%s' can see all messages.\n" ++ " Pass -q to turn off this notice.", s); ++ return 1; + } ++#endif + +- return 0; ++ /* If no ACLs were found, print a short version of the message. */ ++ log_notice("Hint: You are currently not seeing messages from other users and the system.\n" ++ " Users in the 'systemd-journal' group can see all messages. Pass -q to\n" ++ " turn off this notice."); ++ ++ return 1; + } +-#endif + + static int access_check(sd_journal *j) { + Iterator it; +@@ -1746,30 +1761,15 @@ static int access_check(sd_journal *j) { + if (set_isempty(j->errors)) { + if (ordered_hashmap_isempty(j->files)) + log_notice("No journal files were found."); ++ + return 0; + } + + if (set_contains(j->errors, INT_TO_PTR(-EACCES))) { +-#ifdef HAVE_ACL +- /* If /run/log/journal or /var/log/journal exist, try +- to pring a nice notice if the user lacks access to it. */ +- if (!arg_quiet && geteuid() != 0) { +- r = access_check_var_log_journal(j); +- if (r < 0) +- return r; +- } +-#else +- if (geteuid() != 0 && in_group("systemd-journal") <= 0) { +- log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n" +- "group may access messages."); +- return -EACCES; +- } +-#endif ++ (void) access_check_var_log_journal(j); + +- if (ordered_hashmap_isempty(j->files)) { +- log_error("No journal files were opened due to insufficient permissions."); +- r = -EACCES; +- } ++ if (ordered_hashmap_isempty(j->files)) ++ r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions."); + } + + SET_FOREACH(code, j->errors, it) { +@@ -1778,8 +1778,12 @@ static int access_check(sd_journal *j) { + err = -PTR_TO_INT(code); + assert(err > 0); + +- if (err != EACCES) +- log_warning_errno(err, "Error was encountered while opening journal files: %m"); ++ if (err == EACCES) ++ continue; ++ ++ log_warning_errno(err, "Error was encountered while opening journal files: %m"); ++ if (r == 0) ++ r = -err; + } + + return r; +diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c +index e67e9ac..d18a02f 100644 +--- a/src/shared/acl-util.c ++++ b/src/shared/acl-util.c +@@ -82,17 +82,18 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { + + if (tag == ACL_MASK) + return 0; +- if (IN_SET(tag, ACL_USER, ACL_GROUP)) +- goto calc; ++ ++ if (IN_SET(tag, ACL_USER, ACL_GROUP)) { ++ if (acl_calc_mask(acl_p) < 0) ++ return -errno; ++ ++ return 1; ++ } + } + if (r < 0) + return -errno; +- return 0; + +-calc: +- if (acl_calc_mask(acl_p) < 0) +- return -errno; +- return 1; ++ return 0; + } + + int add_base_acls_if_needed(acl_t *acl_p, const char *path) { +@@ -159,59 +160,68 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) { + return 0; + } + +-int search_acl_groups(char*** dst, const char* path, bool* belong) { +- acl_t acl; ++int acl_search_groups(const char *path, char ***ret_groups) { ++ _cleanup_strv_free_ char **g = NULL; ++ _cleanup_(acl_free) acl_t acl = NULL; ++ bool ret = false; ++ acl_entry_t entry; ++ int r; + + assert(path); +- assert(belong); + + acl = acl_get_file(path, ACL_TYPE_DEFAULT); +- if (acl) { +- acl_entry_t entry; +- int r; +- +- r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); +- while (r > 0) { +- acl_tag_t tag; +- gid_t *gid; +- char *name; ++ if (!acl) ++ return -errno; + +- r = acl_get_tag_type(entry, &tag); +- if (r < 0) +- break; ++ r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); ++ for (;;) { ++ _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL; ++ acl_tag_t tag; ++ ++ if (r < 0) ++ return -errno; ++ if (r == 0) ++ break; ++ ++ if (acl_get_tag_type(entry, &tag) < 0) ++ return -errno; + +- if (tag != ACL_GROUP) +- goto next; ++ if (tag != ACL_GROUP) ++ goto next; + +- gid = acl_get_qualifier(entry); +- if (!gid) +- break; ++ gid = acl_get_qualifier(entry); ++ if (!gid) ++ return -errno; ++ ++ if (in_gid(*gid) > 0) { ++ if (!ret_groups) ++ return true; + +- if (in_gid(*gid) > 0) { +- *belong = true; +- break; +- } ++ ret = true; ++ } ++ ++ if (ret_groups) { ++ char *name; + + name = gid_to_name(*gid); +- if (!name) { +- acl_free(acl); +- return log_oom(); +- } +- +- r = strv_consume(dst, name); +- if (r < 0) { +- acl_free(acl); +- return log_oom(); +- } +- +- next: +- r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); ++ if (!name) ++ return -ENOMEM; ++ ++ r = strv_consume(&g, name); ++ if (r < 0) ++ return r; + } + +- acl_free(acl); ++ next: ++ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); + } + +- return 0; ++ if (ret_groups) { ++ *ret_groups = g; ++ g = NULL; ++ } ++ ++ return ret; + } + + int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) { +diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h +index fdb9006..c8bcc26 100644 +--- a/src/shared/acl-util.h ++++ b/src/shared/acl-util.h +@@ -32,7 +32,7 @@ + int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry); + int calc_acl_mask_if_needed(acl_t *acl_p); + int add_base_acls_if_needed(acl_t *acl_p, const char *path); +-int search_acl_groups(char*** dst, const char* path, bool* belong); ++int acl_search_groups(const char* path, char ***ret_groups); + int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask); + int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl); + diff --git a/SOURCES/0378-journalctl-Improve-boot-ID-lookup.patch b/SOURCES/0378-journalctl-Improve-boot-ID-lookup.patch new file mode 100644 index 0000000..4aab7e3 --- /dev/null +++ b/SOURCES/0378-journalctl-Improve-boot-ID-lookup.patch @@ -0,0 +1,55 @@ +From a6db5931947acb807b37cac9c832d68cd66fbc2a Mon Sep 17 00:00:00 2001 +From: Jan Janssen +Date: Fri, 1 May 2015 15:15:16 +0200 +Subject: [PATCH] journalctl: Improve boot ID lookup + +This method should greatly improve offset based lookup, by simply jumping +from one boot to the next boot. It starts at the journal head to get the +a boot ID, makes a _BOOT_ID match and then comes from the opposite +journal direction (tail) to get to the end that boot. After flushing the matches +and advancing the journal from that exact position, we arrive at the start +of next boot. Rinse and repeat. + +This is faster than the old method of aggregating the full boot listing just +so we can jump to a specific boot, which can be a real pain on big journals +just for a mere "-b -1" case. + +As an additional benefit --list-boots should improve slightly too, because +it does less seeking. + +Note that there can be a change in boot order with this lookup method +because it will use the order of boots in the journal, not the realtime stamp +stored in them. That's arguably better, though. +Another deficiency is that it will get confused with boots interleaving in the +journal, therefore, it will refuse operation in --merge, --file and --directory mode. + +https://bugs.freedesktop.org/show_bug.cgi?id=72601 + +Conflicts: + src/journal/journalctl.c + +Cherry-picked from: 596a23293d28f93843aef86721b90043e74d3081 +Related: #1318994 +--- + src/journal/journalctl.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index f60e641..c7a19f2 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1166,11 +1166,10 @@ static int add_boot(sd_journal *j) { + const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r); + + if (sd_id128_is_null(arg_boot_id)) +- log_error("Data from the specified boot (%+i) is not available: %s", +- arg_boot_offset, reason); ++ log_error("Failed to look up boot %+i: %s", arg_boot_offset, reason); + else +- log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s", +- SD_ID128_FORMAT_VAL(arg_boot_id), reason); ++ log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s", ++ SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, reason); + + return r == 0 ? -ENODATA : r; + } diff --git a/SOURCES/0379-journalctl-only-have-a-single-exit-path-from-main.patch b/SOURCES/0379-journalctl-only-have-a-single-exit-path-from-main.patch new file mode 100644 index 0000000..0e5da0f --- /dev/null +++ b/SOURCES/0379-journalctl-only-have-a-single-exit-path-from-main.patch @@ -0,0 +1,217 @@ +From 134a85fc4fa6d1c3209e11415b2610147e2e1aac Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 18 May 2015 23:50:34 +0200 +Subject: [PATCH] journalctl: only have a single exit path from main() + +That way we can be sure we execute the destructors properly, and can be +valgrind-clean. + +Cherry-picked from: 909dea0c7ced0042fa3acd8cd05f5007a2cf2cea +Related: #1318994 +--- + src/journal/journalctl.c | 51 +++++++++++++++++++++++++----------------------- + 1 file changed, 27 insertions(+), 24 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index c7a19f2..31da357 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -532,7 +532,7 @@ static int parse_argv(int argc, char *argv[]) { + arg_boot = true; + + if (optarg) { +- r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset); ++ r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset); + if (r < 0) { + log_error("Failed to parse boot descriptor '%s'", optarg); + return -EINVAL; +@@ -1929,12 +1929,12 @@ int main(int argc, char *argv[]) { + if (r < 0) { + log_error_errno(r, "Failed to open %s: %m", + arg_directory ? arg_directory : arg_file ? "files" : "journal"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = access_check(j); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + + if (arg_action == ACTION_VERIFY) { + r = verify(j); +@@ -1943,7 +1943,8 @@ int main(int argc, char *argv[]) { + + if (arg_action == ACTION_PRINT_HEADER) { + journal_print_header(j); +- return EXIT_SUCCESS; ++ r = 0; ++ goto finish; + } + + if (arg_action == ACTION_DISK_USAGE) { +@@ -1952,11 +1953,11 @@ int main(int argc, char *argv[]) { + + r = sd_journal_get_usage(j, &bytes); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + + printf("Archived and active journals take up %s on disk.\n", + format_bytes(sbytes, sizeof(sbytes), bytes)); +- return EXIT_SUCCESS; ++ goto finish; + } + + if (arg_action == ACTION_VACUUM) { +@@ -1976,7 +1977,7 @@ int main(int argc, char *argv[]) { + } + } + +- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; ++ goto finish; + } + + if (arg_action == ACTION_LIST_BOOTS) { +@@ -1995,11 +1996,11 @@ int main(int argc, char *argv[]) { + * It may need to seek the journal to find parent boot IDs. */ + r = add_boot(j); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + + r = add_dmesg(j); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + + r = add_units(j); + strv_free(arg_system_units); +@@ -2007,25 +2008,25 @@ int main(int argc, char *argv[]) { + + if (r < 0) { + log_error_errno(r, "Failed to add filter for units: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = add_syslog_identifier(j); + if (r < 0) { + log_error_errno(r, "Failed to add filter for syslog identifiers: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = add_priorities(j); + if (r < 0) { + log_error_errno(r, "Failed to add filter for priorities: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = add_matches(j, argv + optind); + if (r < 0) { + log_error_errno(r, "Failed to add filters: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) { +@@ -2042,13 +2043,13 @@ int main(int argc, char *argv[]) { + r = sd_journal_set_data_threshold(j, 0); + if (r < 0) { + log_error("Failed to unset data size threshold"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = sd_journal_query_unique(j, arg_field); + if (r < 0) { + log_error_errno(r, "Failed to query unique data objects: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + SD_JOURNAL_FOREACH_UNIQUE(j, data, size) { +@@ -2066,22 +2067,24 @@ int main(int argc, char *argv[]) { + n_shown ++; + } + +- return EXIT_SUCCESS; ++ r = 0; ++ goto finish; + } + + /* Opening the fd now means the first sd_journal_wait() will actually wait */ + if (arg_follow) { + r = sd_journal_get_fd(j); + if (r < 0) +- return EXIT_FAILURE; ++ goto finish; + } + + if (arg_cursor || arg_after_cursor) { + r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor); + if (r < 0) { + log_error_errno(r, "Failed to seek to cursor: %m"); +- return EXIT_FAILURE; ++ goto finish; + } ++ + if (!arg_reverse) + r = sd_journal_next_skip(j, 1 + !!arg_after_cursor); + else +@@ -2099,7 +2102,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_realtime_usec(j, arg_since); + if (r < 0) { + log_error_errno(r, "Failed to seek to date: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + r = sd_journal_next(j); + +@@ -2107,7 +2110,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_realtime_usec(j, arg_until); + if (r < 0) { + log_error_errno(r, "Failed to seek to date: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + r = sd_journal_previous(j); + +@@ -2115,7 +2118,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_tail(j); + if (r < 0) { + log_error_errno(r, "Failed to seek to tail: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = sd_journal_previous_skip(j, arg_lines); +@@ -2124,7 +2127,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_tail(j); + if (r < 0) { + log_error_errno(r, "Failed to seek to tail: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = sd_journal_previous(j); +@@ -2133,7 +2136,7 @@ int main(int argc, char *argv[]) { + r = sd_journal_seek_head(j); + if (r < 0) { + log_error_errno(r, "Failed to seek to head: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + r = sd_journal_next(j); +@@ -2141,7 +2144,7 @@ int main(int argc, char *argv[]) { + + if (r < 0) { + log_error_errno(r, "Failed to iterate through journal: %m"); +- return EXIT_FAILURE; ++ goto finish; + } + + if (r == 0) { diff --git a/SOURCES/0380-journalctl-free-all-command-line-argument-objects.patch b/SOURCES/0380-journalctl-free-all-command-line-argument-objects.patch new file mode 100644 index 0000000..3e53a70 --- /dev/null +++ b/SOURCES/0380-journalctl-free-all-command-line-argument-objects.patch @@ -0,0 +1,45 @@ +From 4cbe0933587385ed0d811ce11264d65d15b05cfd Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 18 May 2015 23:54:05 +0200 +Subject: [PATCH] journalctl: free all command line argument objects + +let's try to be valgrind clean + +Cherry-picked from: d52da2057f06c49d50ed99300dc407c0227b1a32 +Related: #1318994 +--- + src/journal/journalctl.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 31da357..92ee3fb 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -39,7 +39,6 @@ + + #include "sd-journal.h" + #include "sd-bus.h" +- + #include "log.h" + #include "logs-show.h" + #include "util.h" +@@ -2003,9 +2002,6 @@ int main(int argc, char *argv[]) { + goto finish; + + r = add_units(j); +- strv_free(arg_system_units); +- strv_free(arg_user_units); +- + if (r < 0) { + log_error_errno(r, "Failed to add filter for units: %m"); + goto finish; +@@ -2283,5 +2279,9 @@ finish: + + strv_free(arg_file); + ++ strv_free(arg_syslog_identifier); ++ strv_free(arg_system_units); ++ strv_free(arg_user_units); ++ + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + } diff --git a/SOURCES/0381-journalctl-rename-boot_id_t-to-BootId.patch b/SOURCES/0381-journalctl-rename-boot_id_t-to-BootId.patch new file mode 100644 index 0000000..32478bf --- /dev/null +++ b/SOURCES/0381-journalctl-rename-boot_id_t-to-BootId.patch @@ -0,0 +1,120 @@ +From 1b84db099fc619719026679236a9db0199fd129a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 00:24:27 +0200 +Subject: [PATCH] journalctl: rename boot_id_t to BootId + +So far we tried to reserve the _t suffix to types we use like a value in +contrast to types we use as objects, hence let's do this in journalctl +too. + +Cherry-picked from: 45bc27b621c51b9d0e0229835deb6d188bcd417b +Related: #1318994 +--- + src/journal/journalctl.c | 42 +++++++++++++++++++++++------------------- + 1 file changed, 23 insertions(+), 19 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 92ee3fb..e84dd4c 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -128,12 +128,12 @@ static enum { + ACTION_VACUUM, + } arg_action = ACTION_SHOW; + +-typedef struct boot_id_t { ++typedef struct BootId { + sd_id128_t id; + uint64_t first; + uint64_t last; +- LIST_FIELDS(struct boot_id_t, boot_list); +-} boot_id_t; ++ LIST_FIELDS(struct BootId, boot_list); ++} BootId; + + static int add_matches_for_device(sd_journal *j, const char *devpath) { + int r; +@@ -934,13 +934,15 @@ static int add_matches(sd_journal *j, char **args) { + return 0; + } + +-static int discover_next_boot(sd_journal *j, +- boot_id_t **boot, +- bool advance_older, +- bool read_realtime) { ++static int discover_next_boot( ++ sd_journal *j, ++ BootId **boot, ++ bool advance_older, ++ bool read_realtime) { ++ + int r; + char match[9+32+1] = "_BOOT_ID="; +- _cleanup_free_ boot_id_t *next_boot = NULL; ++ _cleanup_free_ BootId *next_boot = NULL; + + assert(j); + assert(boot); +@@ -965,7 +967,7 @@ static int discover_next_boot(sd_journal *j, + else if (r == 0) + return 0; /* End of journal, yay. */ + +- next_boot = new0(boot_id_t, 1); ++ next_boot = new0(BootId, 1); + if (!next_boot) + return log_oom(); + +@@ -1012,13 +1014,15 @@ static int discover_next_boot(sd_journal *j, + return 0; + } + +-static int get_boots(sd_journal *j, +- boot_id_t **boots, +- boot_id_t *query_ref_boot, +- int ref_boot_offset) { ++static int get_boots( ++ sd_journal *j, ++ BootId **boots, ++ BootId *query_ref_boot, ++ int ref_boot_offset) { ++ + bool skip_once; + int r, count = 0; +- boot_id_t *head = NULL, *tail = NULL; ++ BootId *head = NULL, *tail = NULL; + const bool advance_older = query_ref_boot && ref_boot_offset <= 0; + + assert(j); +@@ -1073,12 +1077,12 @@ static int get_boots(sd_journal *j, + /* No sd_journal_next/previous here. */ + } + +- while (true) { +- _cleanup_free_ boot_id_t *current = NULL; ++ for (;;) { ++ _cleanup_free_ BootId *current = NULL; + + r = discover_next_boot(j, ¤t, advance_older, !query_ref_boot); + if (r < 0) { +- boot_id_t *id, *id_next; ++ BootId *id, *id_next; + LIST_FOREACH_SAFE(boot_list, id, id_next, head) + free(id); + return r; +@@ -1116,7 +1120,7 @@ finish: + + static int list_boots(sd_journal *j) { + int w, i, count; +- boot_id_t *id, *id_next, *all_ids; ++ BootId *id, *id_next, *all_ids; + + assert(j); + +@@ -1148,7 +1152,7 @@ static int list_boots(sd_journal *j) { + static int add_boot(sd_journal *j) { + char match[9+32+1] = "_BOOT_ID="; + int r; +- boot_id_t ref_boot_id = {}; ++ BootId ref_boot_id = {}; + + assert(j); + diff --git a/SOURCES/0382-util-introduce-CMSG_FOREACH-macro-and-make-use-of-it.patch b/SOURCES/0382-util-introduce-CMSG_FOREACH-macro-and-make-use-of-it.patch new file mode 100644 index 0000000..864ec1e --- /dev/null +++ b/SOURCES/0382-util-introduce-CMSG_FOREACH-macro-and-make-use-of-it.patch @@ -0,0 +1,301 @@ +From 603edc22d0516044b72b09ed94a696edd2de7f37 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 10 Jun 2015 19:10:47 +0200 +Subject: [PATCH] util: introduce CMSG_FOREACH() macro and make use of it + everywhere + +It's only marginally shorter then the usual for() loop, but certainly +more readable. + +Cherry-picked from: 2a1288ff89322a2f49c79f6d1832c8164c14a05c +Related: #1318994 +--- + src/core/manager.c | 2 +- + src/core/namespace.c | 3 +-- + src/import/importd.c | 8 ++------ + src/journal/journald-server.c | 2 +- + src/libsystemd-network/sd-dhcp-client.c | 2 +- + src/libsystemd-network/sd-dhcp-server.c | 2 +- + src/libsystemd/sd-bus/bus-container.c | 2 +- + src/libsystemd/sd-bus/bus-socket.c | 16 ++++++++++------ + src/libsystemd/sd-rtnl/rtnl-message.c | 2 +- + src/resolve/resolved-dns-stream.c | 3 ++- + src/resolve/resolved-manager.c | 2 +- + src/shared/macro.h | 3 +++ + src/shared/util.c | 12 +++++++++++- + src/shared/util.h | 2 ++ + src/timesync/timesyncd-manager.c | 2 +- + 15 files changed, 39 insertions(+), 24 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index c502199..71dd70c 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1679,7 +1679,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t + return -errno; + } + +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { ++ CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + + fd_array = (int*) CMSG_DATA(cmsg); +diff --git a/src/core/namespace.c b/src/core/namespace.c +index ebd5fb3..00495c1 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -658,12 +658,11 @@ int setup_netns(int netns_storage_socket[2]) { + } else { + /* Yay, found something, so let's join the namespace */ + +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int))); + netns = *(int*) CMSG_DATA(cmsg); + } +- } + + if (setns(netns, CLONE_NEWNET) < 0) { + r = -errno; +diff --git a/src/import/importd.c b/src/import/importd.c +index 9aaf991..a29630b 100644 +--- a/src/import/importd.c ++++ b/src/import/importd.c +@@ -507,12 +507,8 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void + return -errno; + } + +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { +- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { +- close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); +- log_warning("Somebody sent us unexpected fds, ignoring."); +- return 0; +- } else if (cmsg->cmsg_level == SOL_SOCKET && ++ CMSG_FOREACH(cmsg, &msghdr) { ++ if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 6a35ebb..1eb1394 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1176,7 +1176,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void + return -errno; + } + +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { ++ CMSG_FOREACH(cmsg, &msghdr) { + + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && +diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c +index 5f90617..870850e 100644 +--- a/src/libsystemd-network/sd-dhcp-client.c ++++ b/src/libsystemd-network/sd-dhcp-client.c +@@ -1590,7 +1590,7 @@ static int client_receive_message_raw(sd_event_source *s, int fd, + } else if ((size_t)len < sizeof(DHCPPacket)) + return 0; + +- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { ++ CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_PACKET && + cmsg->cmsg_type == PACKET_AUXDATA && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) { +diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c +index 0f284eb..c9d0ace 100644 +--- a/src/libsystemd-network/sd-dhcp-server.c ++++ b/src/libsystemd-network/sd-dhcp-server.c +@@ -903,7 +903,7 @@ static int server_receive_message(sd_event_source *s, int fd, + else if ((size_t)len < sizeof(DHCPMessage)) + return 0; + +- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { ++ CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) { +diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c +index d29b98a..10ab714 100644 +--- a/src/libsystemd/sd-bus/bus-container.c ++++ b/src/libsystemd/sd-bus/bus-container.c +@@ -222,7 +222,7 @@ int bus_container_connect_kernel(sd_bus *b) { + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; +diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c +index a3c3a45..ab56ef4 100644 +--- a/src/libsystemd/sd-bus/bus-socket.c ++++ b/src/libsystemd/sd-bus/bus-socket.c +@@ -503,7 +503,6 @@ static int bus_socket_read_auth(sd_bus *b) { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)]; + } control; +- struct cmsghdr *cmsg; + bool handle_cmsg = false; + + assert(b); +@@ -554,8 +553,10 @@ static int bus_socket_read_auth(sd_bus *b) { + + b->rbuffer_size += k; + +- if (handle_cmsg) +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) ++ if (handle_cmsg) { ++ struct cmsghdr *cmsg; ++ ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int j; +@@ -569,6 +570,7 @@ static int bus_socket_read_auth(sd_bus *b) { + } else + log_debug("Got unexpected auxiliary data with level=%d and type=%d", + cmsg->cmsg_level, cmsg->cmsg_type); ++ } + + r = bus_socket_auth_verify(b); + if (r != 0) +@@ -930,7 +932,6 @@ int bus_socket_read_message(sd_bus *bus) { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)]; + } control; +- struct cmsghdr *cmsg; + bool handle_cmsg = false; + + assert(bus); +@@ -976,8 +977,10 @@ int bus_socket_read_message(sd_bus *bus) { + + bus->rbuffer_size += k; + +- if (handle_cmsg) +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) ++ if (handle_cmsg) { ++ struct cmsghdr *cmsg; ++ ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int n, *f; +@@ -1005,6 +1008,7 @@ int bus_socket_read_message(sd_bus *bus) { + } else + log_debug("Got unexpected auxiliary data with level=%d and type=%d", + cmsg->cmsg_level, cmsg->cmsg_type); ++ } + + r = bus_socket_read_message_need(bus, &need); + if (r < 0) +diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c +index 9276bbd..cc84253 100644 +--- a/src/libsystemd/sd-rtnl/rtnl-message.c ++++ b/src/libsystemd/sd-rtnl/rtnl-message.c +@@ -1444,7 +1444,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool + return (errno == EAGAIN || errno == EINTR) ? 0 : -errno; + } + +- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { ++ CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { +diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c +index 4c0b557..7f47e72 100644 +--- a/src/resolve/resolved-dns-stream.c ++++ b/src/resolve/resolved-dns-stream.c +@@ -113,7 +113,8 @@ static int dns_stream_identify(DnsStream *s) { + + mh.msg_control = &control; + mh.msg_controllen = sl; +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { ++ ++ CMSG_FOREACH(cmsg, &mh) { + + if (cmsg->cmsg_level == IPPROTO_IPV6) { + assert(s->peer.sa.sa_family == AF_INET6); +diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c +index 7c253aa..173ab8a 100644 +--- a/src/resolve/resolved-manager.c ++++ b/src/resolve/resolved-manager.c +@@ -920,7 +920,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { + } else + return -EAFNOSUPPORT; + +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { ++ CMSG_FOREACH(cmsg, &mh) { + + if (cmsg->cmsg_level == IPPROTO_IPV6) { + assert(p->family == AF_INET6); +diff --git a/src/shared/macro.h b/src/shared/macro.h +index 9d857dc..7a57f4e 100644 +--- a/src/shared/macro.h ++++ b/src/shared/macro.h +@@ -471,4 +471,7 @@ static inline bool GID_IS_INVALID(gid_t gid) { + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + ++#define CMSG_FOREACH(cmsg, mh) \ ++ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) ++ + #include "log.h" +diff --git a/src/shared/util.c b/src/shared/util.c +index 4c441a5..357fbfe 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -7887,7 +7887,7 @@ int openpt_in_namespace(pid_t pid, int flags) { + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + +- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) ++ CMSG_FOREACH(cmsg, &mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; +@@ -8375,6 +8375,16 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k + return -1; + } + ++void cmsg_close_all(struct msghdr *mh) { ++ struct cmsghdr *cmsg; ++ ++ assert(mh); ++ ++ CMSG_FOREACH(cmsg, mh) ++ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) ++ close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); ++} ++ + char *shell_maybe_quote(const char *s) { + const char *p; + char *r, *t; +diff --git a/src/shared/util.h b/src/shared/util.h +index be04524..12afcc3 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -1082,6 +1082,8 @@ void sigkill_wait(pid_t *pid); + + int syslog_parse_priority(const char **p, int *priority, bool with_facility); + ++void cmsg_close_all(struct msghdr *mh); ++ + char *shell_maybe_quote(const char *s); + + typedef enum ExtractFlags { +diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c +index 73ac7ee..5cc1968 100644 +--- a/src/timesync/timesyncd-manager.c ++++ b/src/timesync/timesyncd-manager.c +@@ -539,7 +539,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re + } + + recv_time = NULL; +- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { ++ CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level != SOL_SOCKET) + continue; + diff --git a/SOURCES/0383-journald-don-t-employ-inner-loop-for-reading-from-in.patch b/SOURCES/0383-journald-don-t-employ-inner-loop-for-reading-from-in.patch new file mode 100644 index 0000000..1811890 --- /dev/null +++ b/SOURCES/0383-journald-don-t-employ-inner-loop-for-reading-from-in.patch @@ -0,0 +1,251 @@ +From 6d1ef1fb841a0b3b4c53b560892f3570b3379dc9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 10 Jun 2015 19:24:58 +0200 +Subject: [PATCH] journald: don't employ inner loop for reading from incoming + sockets + +Otherwise, if the socket is constantly busy we will never return to the +event loop, but we really need to to dispatch other (possibly more +high-priority) events too. Hence, return after dispatching one message +to the event handler, and rely on the event loop calling us back +right-away. + +Fixes #125 + +Related: #1318994 +Cherry-picked from: a315ac4e076c4ce7ce3e5c95792cf916d5e918c5 +--- + src/journal/journald-server.c | 204 +++++++++++++++++++++--------------------- + 1 file changed, 100 insertions(+), 104 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 1eb1394..275224d 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1103,6 +1103,42 @@ finish: + + int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Server *s = userdata; ++ struct ucred *ucred = NULL; ++ struct timeval *tv = NULL; ++ struct cmsghdr *cmsg; ++ char *label = NULL; ++ size_t label_len = 0, m; ++ struct iovec iovec; ++ ssize_t n; ++ int *fds = NULL, v = 0; ++ unsigned n_fds = 0; ++ ++ union { ++ struct cmsghdr cmsghdr; ++ ++ /* We use NAME_MAX space for the SELinux label ++ * here. The kernel currently enforces no ++ * limit, but according to suggestions from ++ * the SELinux people this will change and it ++ * will probably be identical to NAME_MAX. For ++ * now we use that, but this should be updated ++ * one day when the final limit is known. */ ++ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + ++ CMSG_SPACE(sizeof(struct timeval)) + ++ CMSG_SPACE(sizeof(int)) + /* fd */ ++ CMSG_SPACE(NAME_MAX)]; /* selinux label */ ++ } control = {}; ++ ++ union sockaddr_union sa = {}; ++ ++ struct msghdr msghdr = { ++ .msg_iov = &iovec, ++ .msg_iovlen = 1, ++ .msg_control = &control, ++ .msg_controllen = sizeof(control), ++ .msg_name = &sa, ++ .msg_namelen = sizeof(sa), ++ }; + + assert(s); + assert(fd == s->native_fd || fd == s->syslog_fd || fd == s->audit_fd); +@@ -1112,119 +1148,79 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void + return -EIO; + } + +- for (;;) { +- struct ucred *ucred = NULL; +- struct timeval *tv = NULL; +- struct cmsghdr *cmsg; +- char *label = NULL; +- size_t label_len = 0; +- struct iovec iovec; +- +- union { +- struct cmsghdr cmsghdr; +- +- /* We use NAME_MAX space for the SELinux label +- * here. The kernel currently enforces no +- * limit, but according to suggestions from +- * the SELinux people this will change and it +- * will probably be identical to NAME_MAX. For +- * now we use that, but this should be updated +- * one day when the final limit is known. */ +- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + +- CMSG_SPACE(sizeof(struct timeval)) + +- CMSG_SPACE(sizeof(int)) + /* fd */ +- CMSG_SPACE(NAME_MAX)]; /* selinux label */ +- } control = {}; +- union sockaddr_union sa = {}; +- struct msghdr msghdr = { +- .msg_iov = &iovec, +- .msg_iovlen = 1, +- .msg_control = &control, +- .msg_controllen = sizeof(control), +- .msg_name = &sa, +- .msg_namelen = sizeof(sa), +- }; +- +- ssize_t n; +- int *fds = NULL; +- unsigned n_fds = 0; +- int v = 0; +- size_t m; +- +- /* Try to get the right size, if we can. (Not all +- * sockets support SIOCINQ, hence we just try, but +- * don't rely on it. */ +- (void) ioctl(fd, SIOCINQ, &v); +- +- /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */ +- m = PAGE_ALIGN(MAX3((size_t) v + 1, +- (size_t) LINE_MAX, +- ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1); +- +- if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m)) +- return log_oom(); +- +- iovec.iov_base = s->buffer; +- iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */ +- +- n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); +- if (n < 0) { +- if (errno == EINTR || errno == EAGAIN) +- return 0; +- +- log_error_errno(errno, "recvmsg() failed: %m"); +- return -errno; +- } ++ /* Try to get the right size, if we can. (Not all ++ * sockets support SIOCINQ, hence we just try, but ++ * don't rely on it. */ ++ (void) ioctl(fd, SIOCINQ, &v); + +- CMSG_FOREACH(cmsg, &msghdr) { +- +- if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_CREDENTIALS && +- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) +- ucred = (struct ucred*) CMSG_DATA(cmsg); +- else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_SECURITY) { +- label = (char*) CMSG_DATA(cmsg); +- label_len = cmsg->cmsg_len - CMSG_LEN(0); +- } else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SO_TIMESTAMP && +- cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) +- tv = (struct timeval*) CMSG_DATA(cmsg); +- else if (cmsg->cmsg_level == SOL_SOCKET && +- cmsg->cmsg_type == SCM_RIGHTS) { +- fds = (int*) CMSG_DATA(cmsg); +- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); +- } +- } ++ /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */ ++ m = PAGE_ALIGN(MAX3((size_t) v + 1, ++ (size_t) LINE_MAX, ++ ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1); + +- /* And a trailing NUL, just in case */ +- s->buffer[n] = 0; ++ if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m)) ++ return log_oom(); + +- if (fd == s->syslog_fd) { +- if (n > 0 && n_fds == 0) +- server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len); +- else if (n_fds > 0) +- log_warning("Got file descriptors via syslog socket. Ignoring."); ++ iovec.iov_base = s->buffer; ++ iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */ + +- } else if (fd == s->native_fd) { +- if (n > 0 && n_fds == 0) +- server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len); +- else if (n == 0 && n_fds == 1) +- server_process_native_file(s, fds[0], ucred, tv, label, label_len); +- else if (n_fds > 0) +- log_warning("Got too many file descriptors via native socket. Ignoring."); ++ n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); ++ if (n < 0) { ++ if (errno == EINTR || errno == EAGAIN) ++ return 0; + +- } else { +- assert(fd == s->audit_fd); ++ return log_error_errno(errno, "recvmsg() failed: %m"); ++ } + +- if (n > 0 && n_fds == 0) +- server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen); +- else if (n_fds > 0) +- log_warning("Got file descriptors via audit socket. Ignoring."); ++ CMSG_FOREACH(cmsg, &msghdr) { ++ ++ if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_CREDENTIALS && ++ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) ++ ucred = (struct ucred*) CMSG_DATA(cmsg); ++ else if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_SECURITY) { ++ label = (char*) CMSG_DATA(cmsg); ++ label_len = cmsg->cmsg_len - CMSG_LEN(0); ++ } else if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SO_TIMESTAMP && ++ cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) ++ tv = (struct timeval*) CMSG_DATA(cmsg); ++ else if (cmsg->cmsg_level == SOL_SOCKET && ++ cmsg->cmsg_type == SCM_RIGHTS) { ++ fds = (int*) CMSG_DATA(cmsg); ++ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + } ++ } ++ ++ /* And a trailing NUL, just in case */ ++ s->buffer[n] = 0; ++ ++ if (fd == s->syslog_fd) { ++ if (n > 0 && n_fds == 0) ++ server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len); ++ else if (n_fds > 0) ++ log_warning("Got file descriptors via syslog socket. Ignoring."); ++ ++ } else if (fd == s->native_fd) { ++ if (n > 0 && n_fds == 0) ++ server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len); ++ else if (n == 0 && n_fds == 1) ++ server_process_native_file(s, fds[0], ucred, tv, label, label_len); ++ else if (n_fds > 0) ++ log_warning("Got too many file descriptors via native socket. Ignoring."); + +- close_many(fds, n_fds); ++ } else { ++ assert(fd == s->audit_fd); ++ ++ if (n > 0 && n_fds == 0) ++ server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen); ++ else if (n_fds > 0) ++ log_warning("Got file descriptors via audit socket. Ignoring."); + } ++ ++ close_many(fds, n_fds); ++ return 0; + } + + static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { diff --git a/SOURCES/0384-journald-fix-count-of-object-meta-fields.patch b/SOURCES/0384-journald-fix-count-of-object-meta-fields.patch new file mode 100644 index 0000000..c41559a --- /dev/null +++ b/SOURCES/0384-journald-fix-count-of-object-meta-fields.patch @@ -0,0 +1,29 @@ +From 7eee42f5d268084171d435de2b16333d2a0f79ab Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 5 Aug 2015 11:31:52 +0300 +Subject: [PATCH] journald: fix count of object meta fields + +There are 12 object meta fields created in dispatch_message_real(), but +we only allocated space for 11. Fix this. + +Fixes #866. + +Cherry-picked from: 704e4fe7a18a13a8651c0064ef3eda91027baffc +Related: #1318994 +--- + src/journal/journald-server.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h +index c96877c..b1263a7 100644 +--- a/src/journal/journald-server.h ++++ b/src/journal/journald-server.h +@@ -148,7 +148,7 @@ typedef struct Server { + #define N_IOVEC_META_FIELDS 20 + #define N_IOVEC_KERNEL_FIELDS 64 + #define N_IOVEC_UDEV_FIELDS 32 +-#define N_IOVEC_OBJECT_FIELDS 11 ++#define N_IOVEC_OBJECT_FIELDS 12 + + void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid); + void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,4); diff --git a/SOURCES/0385-journal-cat-return-a-correct-error-not-1.patch b/SOURCES/0385-journal-cat-return-a-correct-error-not-1.patch new file mode 100644 index 0000000..30d010b --- /dev/null +++ b/SOURCES/0385-journal-cat-return-a-correct-error-not-1.patch @@ -0,0 +1,24 @@ +From ced1149f5af28ce2ad6174a2df9483b483d5e1cf Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 23 Sep 2015 19:39:30 +0200 +Subject: [PATCH] journal-cat: return a correct error, not -1 + +Cherry-picked from: e4603df5cf80bbd7a7d51fc66fa6c60e042423bc +Related: #1318994 +--- + src/journal/cat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/cat.c b/src/journal/cat.c +index 79706b6..ed467b0 100644 +--- a/src/journal/cat.c ++++ b/src/journal/cat.c +@@ -96,7 +96,7 @@ static int parse_argv(int argc, char *argv[]) { + arg_priority = log_level_from_string(optarg); + if (arg_priority < 0) { + log_error("Failed to parse priority value."); +- return arg_priority; ++ return -EINVAL; + } + break; + diff --git a/SOURCES/0386-journalctl-introduce-short-options-for-since-and-unt.patch b/SOURCES/0386-journalctl-introduce-short-options-for-since-and-unt.patch new file mode 100644 index 0000000..ec754dc --- /dev/null +++ b/SOURCES/0386-journalctl-introduce-short-options-for-since-and-unt.patch @@ -0,0 +1,90 @@ +From f6cf4e14409d25868caccc3606a928a610465405 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 13 Oct 2015 10:50:49 +0200 +Subject: [PATCH] journalctl: introduce short options for --since and --until + +Fixes #1514. + +Cherry-picked from: 66f529249a6b3c3391e732cba44482a498153e16 +Related: #1318994 +--- + man/journalctl.xml | 2 ++ + src/journal/journalctl.c | 16 +++++++--------- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/man/journalctl.xml b/man/journalctl.xml +index 0981fba..dedcf19 100644 +--- a/man/journalctl.xml ++++ b/man/journalctl.xml +@@ -528,7 +528,9 @@ + + + ++ + ++ + + + Start showing entries on or newer than the +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index e84dd4c..ba9ae05 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -274,8 +274,8 @@ static void help(void) { + " --system Show the system journal\n" + " --user Show the user journal for the current user\n" + " -M --machine=CONTAINER Operate on local container\n" +- " --since=DATE Show entries not older than the specified date\n" +- " --until=DATE Show entries not newer than the specified date\n" ++ " -S --since=DATE Show entries not older than the specified date\n" ++ " -U --until=DATE Show entries not newer than the specified date\n" + " -c --cursor=CURSOR Show entries starting at the specified cursor\n" + " --after-cursor=CURSOR Show entries after the specified cursor\n" + " --show-cursor Print the cursor after all the entries\n" +@@ -347,8 +347,6 @@ static int parse_argv(int argc, char *argv[]) { + ARG_VERIFY, + ARG_VERIFY_KEY, + ARG_DISK_USAGE, +- ARG_SINCE, +- ARG_UNTIL, + ARG_AFTER_CURSOR, + ARG_SHOW_CURSOR, + ARG_USER_UNIT, +@@ -398,8 +396,8 @@ static int parse_argv(int argc, char *argv[]) { + { "cursor", required_argument, NULL, 'c' }, + { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, + { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, +- { "since", required_argument, NULL, ARG_SINCE }, +- { "until", required_argument, NULL, ARG_UNTIL }, ++ { "since", required_argument, NULL, 'S' }, ++ { "until", required_argument, NULL, 'U' }, + { "unit", required_argument, NULL, 'u' }, + { "user-unit", required_argument, NULL, ARG_USER_UNIT }, + { "field", required_argument, NULL, 'F' }, +@@ -421,7 +419,7 @@ static int parse_argv(int argc, char *argv[]) { + assert(argc >= 0); + assert(argv); + +- while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0) ++ while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0) + + switch (c) { + +@@ -711,7 +709,7 @@ static int parse_argv(int argc, char *argv[]) { + break; + } + +- case ARG_SINCE: ++ case 'S': + r = parse_timestamp(optarg, &arg_since); + if (r < 0) { + log_error("Failed to parse timestamp: %s", optarg); +@@ -720,7 +718,7 @@ static int parse_argv(int argc, char *argv[]) { + arg_since_set = true; + break; + +- case ARG_UNTIL: ++ case 'U': + r = parse_timestamp(optarg, &arg_until); + if (r < 0) { + log_error("Failed to parse timestamp: %s", optarg); diff --git a/SOURCES/0387-journal-s-Envalid-Invalid.patch b/SOURCES/0387-journal-s-Envalid-Invalid.patch new file mode 100644 index 0000000..f1cae03 --- /dev/null +++ b/SOURCES/0387-journal-s-Envalid-Invalid.patch @@ -0,0 +1,24 @@ +From 80476a1b99601168536e4543124d0532c895c498 Mon Sep 17 00:00:00 2001 +From: Vito Caputo +Date: Fri, 23 Oct 2015 16:12:31 -0700 +Subject: [PATCH] journal: s/Envalid/Invalid/ + +Cherry-picked from: 0c4a83a259c2ff87df83f48cd7ceef37b8746f4f +Related: #1318994 +--- + src/journal/journal-verify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c +index 8a66ac7..250d4c7 100644 +--- a/src/journal/journal-verify.c ++++ b/src/journal/journal-verify.c +@@ -899,7 +899,7 @@ int journal_file_verify( + + r = journal_file_object_verify(f, p, o); + if (r < 0) { +- error(p, "Envalid object contents: %s", strerror(-r)); ++ error(p, "Invalid object contents: %s", strerror(-r)); + goto fail; + } + diff --git a/SOURCES/0388-journald-dispatch-SIGTERM-SIGINT-with-a-low-priority.patch b/SOURCES/0388-journald-dispatch-SIGTERM-SIGINT-with-a-low-priority.patch new file mode 100644 index 0000000..fefb1b5 --- /dev/null +++ b/SOURCES/0388-journald-dispatch-SIGTERM-SIGINT-with-a-low-priority.patch @@ -0,0 +1,43 @@ +From be21e10cf30e66215e986ab900637b32e502a29a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 10 Nov 2015 16:53:00 +0100 +Subject: [PATCH] journald: dispatch SIGTERM/SIGINT with a low priority + +Let's make sure to process all queued log data before exiting, so that +we don't unnecessary lose messages when shutting down. + +https://github.com/systemd/systemd/pull/1812#issuecomment-155149871 + +Cherry-picked from: b374689c02c681671a3c3c0b0fd3add32386b442 +Related: #1318994 +--- + src/journal/journald-server.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 275224d..2b7ecd0 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1284,10 +1284,22 @@ static int setup_signals(Server *s) { + if (r < 0) + return r; + ++ /* Let's process SIGTERM late, so that we flush all queued ++ * messages to disk before we exit */ ++ r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20); ++ if (r < 0) ++ return r; ++ ++ /* When journald is invoked on the terminal (when debugging), ++ * it's useful if C-c is handled equivalent to SIGTERM. */ + r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s); + if (r < 0) + return r; + ++ r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20); ++ if (r < 0) ++ return r; ++ + return 0; + } + diff --git a/SOURCES/0389-lz4-fix-size-check-which-had-no-chance-of-working-on.patch b/SOURCES/0389-lz4-fix-size-check-which-had-no-chance-of-working-on.patch new file mode 100644 index 0000000..2dd758d --- /dev/null +++ b/SOURCES/0389-lz4-fix-size-check-which-had-no-chance-of-working-on.patch @@ -0,0 +1,25 @@ +From 942cfd50b5c03f19cfe1b03040c54b7a460b5593 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 1 Dec 2015 22:53:23 -0500 +Subject: [PATCH] lz4: fix size check which had no chance of working on + big-endian + +Cherry-picked from: b3aa622929f81b44974d182636b1fde8b2a506e5 +Related: #1318994 +--- + src/journal/compress.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/compress.c b/src/journal/compress.c +index c9a3399..4fb09f5 100644 +--- a/src/journal/compress.c ++++ b/src/journal/compress.c +@@ -190,7 +190,7 @@ int decompress_blob_lz4(const void *src, uint64_t src_size, + return -EBADMSG; + + size = le64toh( *(le64_t*)src ); +- if (size < 0 || (le64_t) size != *(le64_t*)src) ++ if (size < 0 || (unsigned) size != le64toh(*(le64_t*)src)) + return -EFBIG; + if ((size_t) size > *dst_alloc_size) { + out = realloc(*dst, size); diff --git a/SOURCES/0390-journal-normalize-priority-of-logging-sources.patch b/SOURCES/0390-journal-normalize-priority-of-logging-sources.patch new file mode 100644 index 0000000..bbdc47e --- /dev/null +++ b/SOURCES/0390-journal-normalize-priority-of-logging-sources.patch @@ -0,0 +1,70 @@ +From c87355bc80da9e2cba7f7723d7c6568dfa56f1a1 Mon Sep 17 00:00:00 2001 +From: Vito Caputo +Date: Fri, 8 Jan 2016 12:11:44 -0800 +Subject: [PATCH] journal: normalize priority of logging sources + +The stream event source has a priority of SD_EVENT_PRIORITY_NORMAL+5, +and stdout source +10, but the native and syslog event sources are left +at the default of 0. + +As a result, any heavy native or syslog logger can cause starvation of +the other loggers. This is trivially demonstrated by running: + + dd if=/dev/urandom bs=8k | od | systemd-cat & # native spammer + systemd-run echo hello & # stream logger + journalctl --follow --output=verbose --no-pager --identifier=echo & + +... and wait, and wait, the "hello" never comes. + +Now kill %1, "hello" arrives finally. + +Cherry-picked from: 48cef29504b1ffc0df9929f2d8b2af2ad74d2b4a +Related: #1318994 +--- + src/journal/journald-native.c | 4 ++++ + src/journal/journald-stream.c | 2 +- + src/journal/journald-syslog.c | 4 ++++ + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c +index 851625d..2c9cf6e 100644 +--- a/src/journal/journald-native.c ++++ b/src/journal/journald-native.c +@@ -457,5 +457,9 @@ int server_open_native_socket(Server*s) { + if (r < 0) + return log_error_errno(r, "Failed to add native server fd to event loop: %m"); + ++ r = sd_event_source_set_priority(s->native_event_source, SD_EVENT_PRIORITY_NORMAL+5); ++ if (r < 0) ++ return log_error_errno(r, "Failed to adjust native event source priority: %m"); ++ + return 0; + } +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index 15a554c..b860714 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -448,7 +448,7 @@ int server_open_stdout_socket(Server *s) { + if (r < 0) + return log_error_errno(r, "Failed to add stdout server fd to event source: %m"); + +- r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10); ++ r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+5); + if (r < 0) + return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m"); + +diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c +index 4e118aa..8602b4a 100644 +--- a/src/journal/journald-syslog.c ++++ b/src/journal/journald-syslog.c +@@ -421,6 +421,10 @@ int server_open_syslog_socket(Server *s) { + if (r < 0) + return log_error_errno(r, "Failed to add syslog server fd to event loop: %m"); + ++ r = sd_event_source_set_priority(s->syslog_event_source, SD_EVENT_PRIORITY_NORMAL+5); ++ if (r < 0) ++ return log_error_errno(r, "Failed to adjust syslog event source priority: %m"); ++ + return 0; + } + diff --git a/SOURCES/0391-Fix-miscalculated-buffer-size-and-uses-of-size-unlim.patch b/SOURCES/0391-Fix-miscalculated-buffer-size-and-uses-of-size-unlim.patch new file mode 100644 index 0000000..c381989 --- /dev/null +++ b/SOURCES/0391-Fix-miscalculated-buffer-size-and-uses-of-size-unlim.patch @@ -0,0 +1,43 @@ +From 573e86d7e9f0038044d5cba2a1a543e24b063a79 Mon Sep 17 00:00:00 2001 +From: Aleksander Adamowski +Date: Mon, 11 Jan 2016 15:26:41 -0800 +Subject: [PATCH] Fix miscalculated buffer size and uses of size-unlimited + sprintf() function. + +Not sure if this results in an exploitable buffer overflow, probably not +since the the int value is likely sanitized somewhere earlier and it's +being put through a bit mask shortly before being used. + +Cherry-picked from: 13f5402c6b734ed4c2b3e8b7c3d3bf6d815e7661 +Related: #1318994 +--- + src/journal/journald-syslog.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c +index 8602b4a..b499a0d 100644 +--- a/src/journal/journald-syslog.c ++++ b/src/journal/journald-syslog.c +@@ -317,7 +317,7 @@ void server_process_syslog_message( + size_t label_len) { + + char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)], +- syslog_facility[sizeof("SYSLOG_FACILITY") + DECIMAL_STR_MAX(int)]; ++ syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)]; + const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL; + struct iovec iovec[N_IOVEC_META_FIELDS + 6]; + unsigned n = 0; +@@ -348,11 +348,11 @@ void server_process_syslog_message( + + IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog"); + +- sprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK); ++ snprintf(syslog_priority, sizeof(syslog_priority), "PRIORITY=%i", priority & LOG_PRIMASK); + IOVEC_SET_STRING(iovec[n++], syslog_priority); + + if (priority & LOG_FACMASK) { +- sprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)); ++ snprintf(syslog_facility, sizeof(syslog_facility), "SYSLOG_FACILITY=%i", LOG_FAC(priority)); + IOVEC_SET_STRING(iovec[n++], syslog_facility); + } + diff --git a/SOURCES/0392-journal-Drop-monotonicity-check-when-appending-to-jo.patch b/SOURCES/0392-journal-Drop-monotonicity-check-when-appending-to-jo.patch new file mode 100644 index 0000000..d1c3c5b --- /dev/null +++ b/SOURCES/0392-journal-Drop-monotonicity-check-when-appending-to-jo.patch @@ -0,0 +1,34 @@ +From e1d77a906fef76c1c8db2132e1d3a407f913444c Mon Sep 17 00:00:00 2001 +From: Klearchos Chaloulos +Date: Tue, 9 Feb 2016 12:14:54 +0200 +Subject: [PATCH] journal: Drop monotonicity check when appending to journal + file + +Remove the check that triggers rotation of the journal file when the +arriving log entry had a monotonic timestamp smaller that the previous +log entry. This check causes unnecessary rotations when journal-remote +was receiving from multiple senders, therefore monotonicity can not be +guaranteed. Also, it does not offer any useful functionality for +systemd-journald. + +Cherry-picked from: ecb6105a1bd8445a123343827d46bb527bcca92f +Related: #1318994 +--- + src/journal/journal-file.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 2a93460..8034b77 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -1419,10 +1419,6 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st + ts = &_ts; + } + +- if (f->tail_entry_monotonic_valid && +- ts->monotonic < le64toh(f->header->tail_entry_monotonic)) +- return -EINVAL; +- + #ifdef HAVE_GCRYPT + r = journal_file_maybe_append_tag(f, ts->realtime); + if (r < 0) diff --git a/SOURCES/0393-journalctl-unify-how-we-free-boot-id-lists-a-bit.patch b/SOURCES/0393-journalctl-unify-how-we-free-boot-id-lists-a-bit.patch new file mode 100644 index 0000000..93b9348 --- /dev/null +++ b/SOURCES/0393-journalctl-unify-how-we-free-boot-id-lists-a-bit.patch @@ -0,0 +1,83 @@ +From 76d6062ebf93614a45f1f74be7a93a9a662c5812 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 00:35:02 +0200 +Subject: [PATCH] journalctl: unify how we free boot id lists a bit + +Instead of use LIST_FOREACH_SAFE, just use the same, seperate destructor +everywhere. + +Cherry-picked from: 9530e0d023b0e9308f19eadf6e42cdc25bc30793 +Related: #1318994 +--- + src/journal/journalctl.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index ba9ae05..5864ff5 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -932,6 +932,15 @@ static int add_matches(sd_journal *j, char **args) { + return 0; + } + ++static void boot_id_free_all(BootId *l) { ++ ++ while (l) { ++ BootId *i = l; ++ LIST_REMOVE(boot_list, l, i); ++ free(i); ++ } ++} ++ + static int discover_next_boot( + sd_journal *j, + BootId **boot, +@@ -1009,6 +1018,7 @@ static int discover_next_boot( + + *boot = next_boot; + next_boot = NULL; ++ + return 0; + } + +@@ -1080,9 +1090,7 @@ static int get_boots( + + r = discover_next_boot(j, ¤t, advance_older, !query_ref_boot); + if (r < 0) { +- BootId *id, *id_next; +- LIST_FOREACH_SAFE(boot_list, id, id_next, head) +- free(id); ++ boot_id_free_all(head); + return r; + } + +@@ -1118,7 +1126,7 @@ finish: + + static int list_boots(sd_journal *j) { + int w, i, count; +- BootId *id, *id_next, *all_ids; ++ BootId *id, *all_ids; + + assert(j); + +@@ -1132,7 +1140,7 @@ static int list_boots(sd_journal *j) { + w = DECIMAL_STR_WIDTH(count - 1) + 1; + + i = 0; +- LIST_FOREACH_SAFE(boot_list, id, id_next, all_ids) { ++ LIST_FOREACH(boot_list, id, all_ids) { + char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX]; + + printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n", +@@ -1141,9 +1149,10 @@ static int list_boots(sd_journal *j) { + format_timestamp_maybe_utc(a, sizeof(a), id->first), + format_timestamp_maybe_utc(b, sizeof(b), id->last)); + i++; +- free(id); + } + ++ boot_id_free_all(all_ids); ++ + return 0; + } + diff --git a/SOURCES/0394-journalctl-don-t-trust-the-per-field-entry-tables-wh.patch b/SOURCES/0394-journalctl-don-t-trust-the-per-field-entry-tables-wh.patch new file mode 100644 index 0000000..1aa83fb --- /dev/null +++ b/SOURCES/0394-journalctl-don-t-trust-the-per-field-entry-tables-wh.patch @@ -0,0 +1,187 @@ +From cc5710c3ad0ff51fa84b736d66d5f70aa0ade2b3 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 25 Apr 2016 18:08:42 +0200 +Subject: [PATCH] journalctl: don't trust the per-field entry tables when + looking for boot IDs + +When appending to a journal file, journald will: + +a) first, append the actual entry to the end of the journal file +b) second, add an offset reference to it to the global entry array stored at + the beginning of the file +c) third, add offset references to it to the per-field entry array stored at + various places of the file + +The global entry array, maintained by b) is used when iterating through the +journal without matches applied. + +The per-field entry array maintained by c) is used when iterating through the +journal with a match for that specific field applied. + +In the wild, there are journal files where a) and b) were completed, but c) +was not before the files were abandoned. This means, that in some cases log +entries are at the end of these files that appear in the global entry array, +but not in the per-field entry array of the _BOOT_ID= field. Now, the +"journalctl --list-boots" command alternatingly uses the global entry array +and the per-field entry array of the _BOOT_ID= field. It seeks to the last +entry of a specific _BOOT_ID=field by having the right match installed, and +then jumps to the next following entry with no match installed anymore, under +the assumption this would bring it to the next boot ID. However, if the +per-field entry wasn't written fully, it might actually turn out that the +global entry array might know one more entry with the same _BOOT_ID, thus +resulting in a indefinite loop around the same _BOOT_ID. + +This patch fixes that, by updating the boot search logic to always continue +reading entries until the boot ID actually changed from the previous. Thus, the +per-field entry array is used as quick jump index (i.e. as an optimization), +but not trusted otherwise. Only the global entry array is trusted. + +This replaces PR #1904, which is actually very similar to this one. However, +this one actually reads the boot ID directly from the entry header, and doesn't +try to read it at all until the read pointer is actually really located on the +first item to read. + +Fixes: #617 + +Replaces: #1904 + +Cherry-picked from: dc00966228ff90c554fd034e588ea55eb605ec52 +Related: #1318994 +--- + src/journal/journalctl.c | 71 ++++++++++++++++++++++++++++-------------------- + 1 file changed, 42 insertions(+), 29 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 5864ff5..723854a 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -941,18 +941,18 @@ static void boot_id_free_all(BootId *l) { + } + } + +-static int discover_next_boot( +- sd_journal *j, +- BootId **boot, ++static int discover_next_boot(sd_journal *j, ++ sd_id128_t previous_boot_id, + bool advance_older, +- bool read_realtime) { ++ BootId **ret) { + +- int r; +- char match[9+32+1] = "_BOOT_ID="; + _cleanup_free_ BootId *next_boot = NULL; ++ char match[9+32+1] = "_BOOT_ID="; ++ sd_id128_t boot_id; ++ int r; + + assert(j); +- assert(boot); ++ assert(ret); + + /* We expect the journal to be on the last position of a boot + * (in relation to the direction we are going), so that the next +@@ -965,29 +965,40 @@ static int discover_next_boot( + * we can actually advance to a *different* boot. */ + sd_journal_flush_matches(j); + +- if (advance_older) +- r = sd_journal_previous(j); +- else +- r = sd_journal_next(j); +- if (r < 0) +- return r; +- else if (r == 0) +- return 0; /* End of journal, yay. */ ++ do { ++ if (advance_older) ++ r = sd_journal_previous(j); ++ else ++ r = sd_journal_next(j); ++ if (r < 0) ++ return r; ++ else if (r == 0) ++ return 0; /* End of journal, yay. */ ++ ++ r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); ++ if (r < 0) ++ return r; ++ ++ /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that ++ * normally, this will only require a single iteration, as we seeked to the last entry of the previous ++ * boot entry already. However, it might happen that the per-journal-field entry arrays are less ++ * complete than the main entry array, and hence might reference an entry that's not actually the last ++ * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to ++ * speed things up, but let's not trust that it is complete, and hence, manually advance as ++ * necessary. */ ++ ++ } while (sd_id128_equal(boot_id, previous_boot_id)); + + next_boot = new0(BootId, 1); + if (!next_boot) + return log_oom(); + +- r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id); ++ next_boot->id = boot_id; ++ ++ r = sd_journal_get_realtime_usec(j, &next_boot->first); + if (r < 0) + return r; + +- if (read_realtime) { +- r = sd_journal_get_realtime_usec(j, &next_boot->first); +- if (r < 0) +- return r; +- } +- + /* Now seek to the last occurrence of this boot ID. */ + sd_id128_to_string(next_boot->id, match + 9); + r = sd_journal_add_match(j, match, sizeof(match) - 1); +@@ -1010,13 +1021,11 @@ static int discover_next_boot( + else if (r == 0) + return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */ + +- if (read_realtime) { +- r = sd_journal_get_realtime_usec(j, &next_boot->last); +- if (r < 0) +- return r; +- } ++ r = sd_journal_get_realtime_usec(j, &next_boot->last); ++ if (r < 0) ++ return r; + +- *boot = next_boot; ++ *ret = next_boot; + next_boot = NULL; + + return 0; +@@ -1032,6 +1041,7 @@ static int get_boots( + int r, count = 0; + BootId *head = NULL, *tail = NULL; + const bool advance_older = query_ref_boot && ref_boot_offset <= 0; ++ sd_id128_t previous_boot_id; + + assert(j); + +@@ -1085,10 +1095,11 @@ static int get_boots( + /* No sd_journal_next/previous here. */ + } + ++ previous_boot_id = SD_ID128_NULL; + for (;;) { + _cleanup_free_ BootId *current = NULL; + +- r = discover_next_boot(j, ¤t, advance_older, !query_ref_boot); ++ r = discover_next_boot(j, previous_boot_id, advance_older, ¤t); + if (r < 0) { + boot_id_free_all(head); + return r; +@@ -1097,6 +1108,8 @@ static int get_boots( + if (!current) + break; + ++ previous_boot_id = current->id; ++ + if (query_ref_boot) { + if (!skip_once) + ref_boot_offset += advance_older ? 1 : -1; diff --git a/SOURCES/0395-units-remove-udev-control-socket-when-systemd-stops-.patch b/SOURCES/0395-units-remove-udev-control-socket-when-systemd-stops-.patch new file mode 100644 index 0000000..cca08e1 --- /dev/null +++ b/SOURCES/0395-units-remove-udev-control-socket-when-systemd-stops-.patch @@ -0,0 +1,33 @@ +From f77d58374ccd2e3d9c886e59020f1b32e97f2bdc Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 29 Aug 2016 14:49:20 +0200 +Subject: [PATCH] units: remove udev control socket when systemd stops the + socket unit (#49) + +Mere presence of the socket in the filesystem makes +udev_queue_get_udev_is_active() return that udev is running. Note that, +udev on exit doesn't unlink control socket nor does systemd. Thus socket +stays around even when both daemon and socket are stopped. This causes +problems for cryptsetup because when it detects running udev it launches +synchronous operations that *really* require udev. This in turn may +cause blocking and subsequent timeout in systemd-cryptsetup on reboot +while machine is in a state that udev and its control socket units are +stopped, e.g. emergency mode. + +Fixes #2477 + +Cherry-picked from: a2de10775194edec51b1e88d20a380724a3dc716 +Resolves: #1370133 +--- + units/systemd-udevd-control.socket | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/systemd-udevd-control.socket b/units/systemd-udevd-control.socket +index 8330a1c..46f704e 100644 +--- a/units/systemd-udevd-control.socket ++++ b/units/systemd-udevd-control.socket +@@ -17,3 +17,4 @@ Service=systemd-udevd.service + ListenSequentialPacket=/run/udev/control + SocketMode=0600 + PassCredentials=yes ++RemoveOnStop=yes diff --git a/SOURCES/0396-logind-don-t-assert-if-the-slice-is-missing.patch b/SOURCES/0396-logind-don-t-assert-if-the-slice-is-missing.patch new file mode 100644 index 0000000..75055f3 --- /dev/null +++ b/SOURCES/0396-logind-don-t-assert-if-the-slice-is-missing.patch @@ -0,0 +1,26 @@ +From 7f681673fa2af8f1898447ee336763f2eeb00d57 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 13 Nov 2015 18:47:02 +0100 +Subject: [PATCH] logind: don't assert if the slice is missing + +After all, we don't actually really need the slice to work, it's just +nice to have it. + +Cherry-picked from: 38599489e49e840291516488a3ef1b4a56198c58 +Resolves: #1371437 +--- + src/login/logind-session.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 59f5a7a..746e50a 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -507,7 +507,6 @@ static int session_start_scope(Session *s) { + + assert(s); + assert(s->user); +- assert(s->user->slice); + + if (!s->scope) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; diff --git a/SOURCES/0397-core-enable-transient-unit-support-for-slice-units.patch b/SOURCES/0397-core-enable-transient-unit-support-for-slice-units.patch new file mode 100644 index 0000000..48f6860 --- /dev/null +++ b/SOURCES/0397-core-enable-transient-unit-support-for-slice-units.patch @@ -0,0 +1,48 @@ +From e360c720533dccac39d8b88510b15c21a944b042 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 13 Nov 2015 18:46:50 +0100 +Subject: [PATCH] core: enable transient unit support for slice units + +Cherry-picked from: 17f62e9bd00f5fefd486475861b06d3ec6b7ee10 +Resolves: #1370299 +--- + src/core/dbus-manager.c | 13 ++++++++++++- + src/core/slice.c | 1 + + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 9eef290..8d3758a 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -633,7 +633,18 @@ static int transient_unit_from_message( + if (r < 0) + return r; + +- if (u->load_state != UNIT_NOT_FOUND || ++ /* Check if the unit already exists or is already referenced, ++ * in a number of different ways. Note that to cater for unit ++ * types such as slice, we are generally fine with units that ++ * are marked UNIT_LOADED even even though nothing was ++ * actually loaded, as those unit types don't require a file ++ * on disk to validly load. */ ++ ++ if (!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) || ++ u->fragment_path || ++ u->source_path || ++ !strv_isempty(u->dropin_paths) || ++ u->refs || + set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); + +diff --git a/src/core/slice.c b/src/core/slice.c +index 61ff9d3..9154558 100644 +--- a/src/core/slice.c ++++ b/src/core/slice.c +@@ -272,6 +272,7 @@ const UnitVTable slice_vtable = { + + .no_alias = true, + .no_instances = true, ++ .can_transient = true, + + .load = slice_load, + diff --git a/SOURCES/0398-sd-bus-bump-message-queue-size.patch b/SOURCES/0398-sd-bus-bump-message-queue-size.patch new file mode 100644 index 0000000..12ac5b5 --- /dev/null +++ b/SOURCES/0398-sd-bus-bump-message-queue-size.patch @@ -0,0 +1,31 @@ +From aff078e9ce3c43410de9bc3a2e9cf7042ac799aa Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 31 Aug 2016 20:09:31 +0200 +Subject: [PATCH] sd-bus: bump message queue size + +Let's bump it further, as this the current limit turns out to be problematic +IRL. Let's bump it to more than twice what we know of is needed. + +Fixes: #4068 + +Cherry-picked from: 5ddda46 +Resolves: #1371205 +--- + src/libsystemd/sd-bus/bus-internal.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h +index 071b3da..6a10686 100644 +--- a/src/libsystemd/sd-bus/bus-internal.h ++++ b/src/libsystemd/sd-bus/bus-internal.h +@@ -326,8 +326,8 @@ struct sd_bus { + + #define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) + +-#define BUS_WQUEUE_MAX 1024 +-#define BUS_RQUEUE_MAX 64*1024 ++#define BUS_WQUEUE_MAX (192*1024) ++#define BUS_RQUEUE_MAX (192*1024) + + #define BUS_MESSAGE_SIZE_MAX (64*1024*1024) + #define BUS_AUTH_SIZE_MAX (64*1024) diff --git a/SOURCES/0399-install-fix-disable-when-etc-systemd-system-is-a-sym.patch b/SOURCES/0399-install-fix-disable-when-etc-systemd-system-is-a-sym.patch new file mode 100644 index 0000000..fc0079d --- /dev/null +++ b/SOURCES/0399-install-fix-disable-when-etc-systemd-system-is-a-sym.patch @@ -0,0 +1,24 @@ +From 30c5299e91db30f07b64c6c47ac7417bd4e6988c Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 30 Aug 2016 15:04:07 +0200 +Subject: [PATCH] install: fix disable when /etc/systemd/system is a symlink + +Cherry-picked from: 67852d08e6a35d34b428e8be64efdb3f003f4697 +Resolves: #1285996 +--- + src/shared/install.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index 61aaafe..ab86cd1 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -476,7 +476,7 @@ static int remove_marked_symlinks( + if (set_size(remove_symlinks_to) <= 0) + return 0; + +- fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); ++ fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); + if (fd < 0) + return -errno; + diff --git a/SOURCES/0400-rules-add-NVMe-rules-3136.patch b/SOURCES/0400-rules-add-NVMe-rules-3136.patch new file mode 100644 index 0000000..ba874de --- /dev/null +++ b/SOURCES/0400-rules-add-NVMe-rules-3136.patch @@ -0,0 +1,36 @@ +From d913c83db4d3271a400173dfee55078335055e86 Mon Sep 17 00:00:00 2001 +From: Ming Lin +Date: Fri, 29 Apr 2016 04:02:57 -0700 +Subject: [PATCH] rules: add NVMe rules (#3136) + +Add NVMe rules using the "wwid" attribute. + +root@target:~# cat /sys/block/nvme0n1/wwid +eui.3825004235000591 + +root@target:~# ls /dev/disk/by-id/ -l |grep nvme +lrwxrwxrwx 1 root root 13 Apr 27 16:08 nvme-eui.3825004235000591 -> ../../nvme0n1 +lrwxrwxrwx 1 root root 15 Apr 27 16:08 nvme-eui.3825004235000591-part1 -> ../../nvme0n1p1 +lrwxrwxrwx 1 root root 15 Apr 27 16:08 nvme-eui.3825004235000591-part2 -> ../../nvme0n1p2 + +Cherry-picked from: 427a28ecbe0eb170e651e0530ab58d6e6f6c498c +Resolves: #1274651 +--- + rules/60-persistent-storage.rules | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index 71ab974..cc01acb 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -22,6 +22,10 @@ TEST=="whole_disk", GOTO="persistent_storage_end" + # for partitions import parent information + ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" + ++# NVMe ++KERNEL=="nvme*[0-9]n*[0-9]", ATTR{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}" ++KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}-part%n" ++ + # virtio-blk + KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" + KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n" diff --git a/SOURCES/0401-rules-introduce-disk-by-id-model_serial-symlinks-for.patch b/SOURCES/0401-rules-introduce-disk-by-id-model_serial-symlinks-for.patch new file mode 100644 index 0000000..a6d5133 --- /dev/null +++ b/SOURCES/0401-rules-introduce-disk-by-id-model_serial-symlinks-for.patch @@ -0,0 +1,36 @@ +From 1e61121501f79e654a36bf2efb6a987f6a11c262 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 17 Aug 2016 14:10:28 +0200 +Subject: [PATCH] rules: introduce disk/by-id (model_serial) symlinks for NVMe + drives (#3974) + +$ ls -l /dev/disk/by-id/nvme* +lrwxrwxrwx. 1 root root 13 Aug 17 04:25 /dev/disk/by-id/nvme-HUSPR3216AHP301_STM0001B6780 -> ../../nvme0n1 +lrwxrwxrwx. 1 root root 15 Aug 17 04:25 /dev/disk/by-id/nvme-HUSPR3216AHP301_STM0001B6780-part1 -> ../../nvme0n1p1 + +https://github.com/systemd/systemd/issues/1453 +https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=779ff75617099f4defe14e20443b95019a4c5ae8 + +Cherry-picked from: a5110c90303cf455db5062faef34d5724d12e2e9 +Related: #1274651 +--- + rules/60-persistent-storage.rules | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index cc01acb..74f8f21 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -26,6 +26,12 @@ ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*" + KERNEL=="nvme*[0-9]n*[0-9]", ATTR{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}" + KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}-part%n" + ++KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" ++KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}" ++ ++KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" ++KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n" ++ + # virtio-blk + KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" + KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n" diff --git a/SOURCES/0402-rules-fix-for-possible-whitespace-in-the-model-attri.patch b/SOURCES/0402-rules-fix-for-possible-whitespace-in-the-model-attri.patch new file mode 100644 index 0000000..504b0e8 --- /dev/null +++ b/SOURCES/0402-rules-fix-for-possible-whitespace-in-the-model-attri.patch @@ -0,0 +1,33 @@ +From 8ed606212fb3e82c12b1fcea8500a5dfe4f89393 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 1 Sep 2016 12:42:05 +0200 +Subject: [PATCH] rules: fix for possible whitespace in the "model" attribute + +Without this the rules would create multiple wrong symlinks, because +SYMLINK treats strings with spaces as a list of links to create. + +Suggested-by: Artur Paszkiewicz + +Cherry-picked from: f41c12825db7460429c857ccc0e545bd631a62a0 +Related: #1274651 +--- + rules/60-persistent-storage.rules | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index 74f8f21..06e3329 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -27,10 +27,10 @@ KERNEL=="nvme*[0-9]n*[0-9]", ATTR{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{w + KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}-part%n" + + KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" +-KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}" ++KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}", OPTIONS="string_escape=replace" + + KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}" +-KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n" ++KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n", OPTIONS="string_escape=replace" + + # virtio-blk + KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" diff --git a/SOURCES/0403-systemctl-pid1-do-not-warn-about-missing-install-inf.patch b/SOURCES/0403-systemctl-pid1-do-not-warn-about-missing-install-inf.patch new file mode 100644 index 0000000..95a1cef --- /dev/null +++ b/SOURCES/0403-systemctl-pid1-do-not-warn-about-missing-install-inf.patch @@ -0,0 +1,111 @@ +From 5f273838f41f27e0045395c1677272d9dd12496c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 21 Apr 2016 20:04:21 -0400 +Subject: [PATCH] systemctl,pid1: do not warn about missing install info with + "preset" + +When "preset" was executed for a unit without install info, we'd warn similarly +as for "enable" and "disable". But "preset" is usually called for all units, +because the preset files are provided by the distribution, and the units are under +control of individual programs, and it's reasonable to call "preset" for all units +rather then try to do it only for the ones that can be installed. +We also don't warn about missing info for "preset-all". Thus it seems reasonable +to silently ignore units w/o install info when presetting. + +(In addition, when more than one unit was specified, we'd issue the warning +only if none of them had install info. But this is probably something to fix +for enable/disable too.) + +Cherry-picked from: 39207373dd638e548019ddb49929f15795b8b404 +Resolves: #1373950 +--- + man/systemctl.xml | 26 +++++++++++++------------- + src/systemctl/systemctl.c | 7 ++++--- + 2 files changed, 17 insertions(+), 16 deletions(-) + +diff --git a/man/systemctl.xml b/man/systemctl.xml +index 2d0678d..bb21f3a 100644 +--- a/man/systemctl.xml ++++ b/man/systemctl.xml +@@ -1012,22 +1012,22 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service + preset NAME... + + +- Reset one or more unit files, as specified on the +- command line, to the defaults configured in the preset +- policy files. This has the same effect as +- disable or enable, +- depending how the unit is listed in the preset files. ++ Reset the enable/disable status one or more unit files, as specified on ++ the command line, to the defaults configured in the preset policy files. This ++ has the same effect as disable or ++ enable, depending how the unit is listed in the preset ++ files. + +- Use to control +- whether units shall be enabled and disabled, or only +- enabled, or only disabled. ++ Use to control whether units shall be ++ enabled and disabled, or only enabled, or only disabled. ++ ++ If the unit carries no install information, it will be silently ignored ++ by this command. + +- For more information on the preset policy format, +- see ++ For more information on the preset policy format, see + systemd.preset5. +- For more information on the concept of presets, please +- consult the Preset ++ For more information on the concept of presets, please consult the ++ Preset + document. + + +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index e4b404a..e854508 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -5367,6 +5367,7 @@ static int enable_unit(sd_bus *bus, char **args) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + int carries_install_info = -1; ++ bool ignore_carries_install_info = false; + int r; + + if (!args[1]) +@@ -5404,7 +5405,6 @@ static int enable_unit(sd_bus *bus, char **args) { + r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + else if (streq(verb, "preset")) { + r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes); +- carries_install_info = r; + } else if (streq(verb, "mask")) + r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + else if (streq(verb, "unmask")) +@@ -5424,7 +5424,7 @@ static int enable_unit(sd_bus *bus, char **args) { + } else { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +- int expect_carries_install_info = false; ++ bool expect_carries_install_info = false; + bool send_force = true, send_preset_mode = false; + const char *method; + +@@ -5450,6 +5450,7 @@ static int enable_unit(sd_bus *bus, char **args) { + method = "PresetUnitFiles"; + + expect_carries_install_info = true; ++ ignore_carries_install_info = true; + } else if (streq(verb, "mask")) + method = "MaskUnitFiles"; + else if (streq(verb, "unmask")) { +@@ -5515,7 +5516,7 @@ static int enable_unit(sd_bus *bus, char **args) { + r = 0; + } + +- if (carries_install_info == 0) ++ if (carries_install_info == 0 && !ignore_carries_install_info) + log_warning("The unit files have no [Install] section. They are not meant to be enabled\n" + "using systemctl.\n" + "Possible reasons for having this kind of units are:\n" diff --git a/SOURCES/0404-systemctl-core-ignore-masked-units-in-preset-all.patch b/SOURCES/0404-systemctl-core-ignore-masked-units-in-preset-all.patch new file mode 100644 index 0000000..f3c6446 --- /dev/null +++ b/SOURCES/0404-systemctl-core-ignore-masked-units-in-preset-all.patch @@ -0,0 +1,148 @@ +From c9a4b1688552a23867d3d9db18620501d57d33da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 16 Apr 2016 19:31:53 -0400 +Subject: [PATCH] systemctl/core: ignore masked units in preset-all + +With any masked unit that would that would be enabled by presets, we'd get: + +test@rawhide $ sudo systemctl preset-all +Failed to execute operation: Unit file is masked. + +test@rawhide $ sudo systemctl --root=/ preset-all +Operation failed: Cannot send after transport endpoint shutdown + +Simply ignore those units: + +test@rawhide $ sudo systemctl preset-all +Unit xxx.service is masked, ignoring. + +Cherry-picked from: 9a0a413a195a21888cf926be5595d0efc1eef0fe +Related: #1375097 +--- + src/core/dbus-manager.c | 12 +++++++----- + src/libsystemd/sd-bus/bus-util.c | 10 ++++++++-- + src/shared/install.c | 4 ++++ + src/shared/install.h | 5 +++++ + src/systemctl/systemctl.c | 20 ++++++++++++++------ + 5 files changed, 38 insertions(+), 13 deletions(-) + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 8d3758a..c2067c0 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -1598,11 +1598,13 @@ static int reply_unit_file_changes_and_free( + unsigned i; + int r; + +- if (n_changes > 0) { +- r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); +- if (r < 0) +- log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); +- } ++ for (i = 0; i < n_changes; i++) ++ if (unit_file_change_is_modification(changes[i].type)) { ++ r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL); ++ if (r < 0) ++ log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m"); ++ break; ++ } + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 9d70798..75d0370 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1893,11 +1893,17 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un + if (!quiet) { + if (streq(type, "symlink")) + log_info("Created symlink from %s to %s.", path, source); +- else ++ else if (streq(type, "unlink")) + log_info("Removed symlink %s.", path); ++ else if (streq(type, "masked")) ++ log_info("Unit %s is masked, ignoring.", path); ++ else ++ log_notice("Manager reported unknown change type \"%s\" for %s.", type, path); + } + +- r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source); ++ r = unit_file_changes_add(changes, n_changes, ++ unit_file_change_type_from_string(type), ++ path, source); + if (r < 0) + return r; + } +diff --git a/src/shared/install.c b/src/shared/install.c +index ab86cd1..62da52d 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2402,6 +2402,9 @@ int unit_file_preset_all( + continue; + + r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name); ++ if (r == -ESHUTDOWN) ++ r = unit_file_changes_add(changes, n_changes, ++ UNIT_FILE_IS_MASKED, de->d_name, NULL); + if (r < 0) + return r; + } +@@ -2535,6 +2538,7 @@ DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); + static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = { + [UNIT_FILE_SYMLINK] = "symlink", + [UNIT_FILE_UNLINK] = "unlink", ++ [UNIT_FILE_IS_MASKED] = "masked", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); +diff --git a/src/shared/install.h b/src/shared/install.h +index 87a40b6..f0e3666 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -60,10 +60,15 @@ typedef enum UnitFilePresetMode { + typedef enum UnitFileChangeType { + UNIT_FILE_SYMLINK, + UNIT_FILE_UNLINK, ++ UNIT_FILE_IS_MASKED, + _UNIT_FILE_CHANGE_TYPE_MAX, + _UNIT_FILE_CHANGE_TYPE_INVALID = -1 + } UnitFileChangeType; + ++static inline bool unit_file_change_is_modification(UnitFileChangeType type) { ++ return IN_SET(type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK); ++} ++ + typedef struct UnitFileChange { + UnitFileChangeType type; + char *path; +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index e4b404a..a688d69 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -1944,12 +1944,20 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha + + assert(changes || n_changes == 0); + +- for (i = 0; i < n_changes; i++) { +- if (changes[i].type == UNIT_FILE_SYMLINK) +- log_info("Created symlink from %s to %s.", changes[i].path, changes[i].source); +- else +- log_info("Removed symlink %s.", changes[i].path); +- } ++ for (i = 0; i < n_changes; i++) ++ switch(changes[i].type) { ++ case UNIT_FILE_SYMLINK: ++ log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); ++ break; ++ case UNIT_FILE_UNLINK: ++ log_info("Removed %s.", changes[i].path); ++ break; ++ case UNIT_FILE_IS_MASKED: ++ log_info("Unit %s is masked, ignoring.", changes[i].path); ++ break; ++ default: ++ assert_not_reached("bad change type"); ++ } + } + + static int set_default(sd_bus *bus, char **args) { diff --git a/SOURCES/0405-shared-install-handle-dangling-aliases-as-an-explici.patch b/SOURCES/0405-shared-install-handle-dangling-aliases-as-an-explici.patch new file mode 100644 index 0000000..abdb752 --- /dev/null +++ b/SOURCES/0405-shared-install-handle-dangling-aliases-as-an-explici.patch @@ -0,0 +1,113 @@ +From 2047b2d0db643a168144b708cf58091ca47acb21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 4 May 2016 10:10:57 -0400 +Subject: [PATCH] shared/install: handle dangling aliases as an explicit case, + report nicely + +This fixes 'preset-all' with a unit that is a dangling symlink. + +$ systemctl --root=/ preset-all +Unit syslog.service is an alias to a unit that is not present, ignoring. +Unit auditd.service is masked, ignoring. +Unit NetworkManager.service is masked, ignoring. + +Cherry-picked from: 893275df36c8c358d3c0b851ca255a6169dac138 +Resolves: #1375097 +--- + src/libsystemd/sd-bus/bus-util.c | 2 ++ + src/shared/install.c | 17 +++++++++++++---- + src/shared/install.h | 1 + + src/systemctl/systemctl.c | 3 +++ + 4 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 75d0370..d357760 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1897,6 +1897,8 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un + log_info("Removed symlink %s.", path); + else if (streq(type, "masked")) + log_info("Unit %s is masked, ignoring.", path); ++ else if (streq(type, "dangling")) ++ log_info("Unit %s is an alias to a unit that is not present, ignoring.", path); + else + log_notice("Manager reported unknown change type \"%s\" for %s.", type, path); + } +diff --git a/src/shared/install.c b/src/shared/install.c +index 62da52d..b0a29dd 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -1253,12 +1253,15 @@ static int install_info_traverse( + if (r < 0) + return r; + ++ /* Try again, with the new target we found. */ + r = unit_file_search(c, i, paths, root_dir, flags); +- if (r < 0) +- return r; ++ if (r == -ENOENT) ++ /* Translate error code to highlight this specific case */ ++ return -ENOLINK; + } + +- /* Try again, with the new target we found. */ ++ if (r < 0) ++ return r; + } + + if (ret) +@@ -1528,7 +1531,9 @@ static int install_context_mark_for_removal( + return r; + + r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); +- if (r < 0) ++ if (r == -ENOLINK) ++ return 0; ++ else if (r < 0) + return r; + + if (i->type != UNIT_FILE_TYPE_REGULAR) +@@ -2405,6 +2410,9 @@ int unit_file_preset_all( + if (r == -ESHUTDOWN) + r = unit_file_changes_add(changes, n_changes, + UNIT_FILE_IS_MASKED, de->d_name, NULL); ++ else if (r == -ENOLINK) ++ r = unit_file_changes_add(changes, n_changes, ++ UNIT_FILE_IS_DANGLING, de->d_name, NULL); + if (r < 0) + return r; + } +@@ -2539,6 +2547,7 @@ static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] + [UNIT_FILE_SYMLINK] = "symlink", + [UNIT_FILE_UNLINK] = "unlink", + [UNIT_FILE_IS_MASKED] = "masked", ++ [UNIT_FILE_IS_DANGLING] = "dangling", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); +diff --git a/src/shared/install.h b/src/shared/install.h +index f0e3666..7e40445 100644 +--- a/src/shared/install.h ++++ b/src/shared/install.h +@@ -61,6 +61,7 @@ typedef enum UnitFileChangeType { + UNIT_FILE_SYMLINK, + UNIT_FILE_UNLINK, + UNIT_FILE_IS_MASKED, ++ UNIT_FILE_IS_DANGLING, + _UNIT_FILE_CHANGE_TYPE_MAX, + _UNIT_FILE_CHANGE_TYPE_INVALID = -1 + } UnitFileChangeType; +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index a688d69..39f0150 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -1955,6 +1955,9 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha + case UNIT_FILE_IS_MASKED: + log_info("Unit %s is masked, ignoring.", changes[i].path); + break; ++ case UNIT_FILE_IS_DANGLING: ++ log_info("Unit %s is an alias to a unit that is not present, ignoring.", changes[i].path); ++ break; + default: + assert_not_reached("bad change type"); + } diff --git a/SOURCES/0406-shared-install-ignore-unit-symlinks-when-doing-prese.patch b/SOURCES/0406-shared-install-ignore-unit-symlinks-when-doing-prese.patch new file mode 100644 index 0000000..025a8ca --- /dev/null +++ b/SOURCES/0406-shared-install-ignore-unit-symlinks-when-doing-prese.patch @@ -0,0 +1,75 @@ +From 412044ee341c574e5163bf2be32e5da9618f2640 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 13 Aug 2016 01:20:29 -0400 +Subject: [PATCH] shared/install: ignore unit symlinks when doing preset-all + +Before, when interating over unit files during preset-all, behaviour was the +following: + +- if we hit the real unit name first, presets were queried for that name, and + that unit was enabled or disabled accordingly, + +- if we hit an alias first (one of the symlinks chaining to the real unit), we + checked the presets using the symlink name, and then proceeded to enable or + disable the real unit. + +E.g. for systemd-networkd.service we have the alias dbus-org.freedesktop.network1.service +(/usr/lib/systemd/system/dbus-org.freedesktop.network1.service), but the preset +is only for the systemd-networkd.service name. The service would be enabled or +disabled pseudorandomly depending on the order of iteration. + +For "preset", behaviour was analogous: preset on the alias name disabled the +service (following the default disable policy), preset on the "real" name +applied the presets. + +With the patch, for "preset" and "preset-all" we silently skip symlinks. This +gives mostly the right behaviour, with the limitation that presets on aliases +are ignored. I think that presets on aliases are not that common (at least my +preset files on Fedora don't exhibit any such usage), and should not be +necessary, since whoever installs the preset can just refer to the real unit +file. It would be possible to overcome this limitation by gathering a list of +names of a unit first, and then checking whether *any* of the names matches the +presets list. That would require a significant redesign of the code, and be +a lot slower (since we would have to fully read all unit directories to preset +one unit) to so I'm not doing that for now. + +With this patch, two properties are satisfied: +- preset-all and preset are idempotent, and the second and subsequent invocations + do not produce any changes, +- preset-all and preset for a specific name produce the same state for that unit. + +Fixes #3616. + +Cherry-picked from: 11e11fd57a837ea1cb142009c3048882392f3ed3 +Related: #1375097 +--- + src/shared/install.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/shared/install.c b/src/shared/install.c +index b0a29dd..f01a212 100644 +--- a/src/shared/install.c ++++ b/src/shared/install.c +@@ -2270,12 +2270,20 @@ static int preset_prepare_one( + const char *name) { + + InstallInfo *i; ++ _cleanup_(install_context_done) InstallContext tmp = {}; + int r; + +- if (install_info_find(plus, name) || +- install_info_find(minus, name)) ++ if (install_info_find(plus, name) || install_info_find(minus, name)) + return 0; + ++ r = install_info_discover(scope, &tmp, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); ++ if (r < 0) ++ return r; ++ if (!streq(name, i->name)) { ++ log_debug("Skipping %s because is an alias for %s", name, i->name); ++ return 0; ++ } ++ + r = unit_file_query_preset(scope, root_dir, name); + if (r < 0) + return r; diff --git a/SOURCES/0407-40-redhat.rules-don-t-hoplug-memory-on-s390x.patch b/SOURCES/0407-40-redhat.rules-don-t-hoplug-memory-on-s390x.patch new file mode 100644 index 0000000..a9e060c --- /dev/null +++ b/SOURCES/0407-40-redhat.rules-don-t-hoplug-memory-on-s390x.patch @@ -0,0 +1,23 @@ +From 195083a33b4204d513787e7f4b6c63f19a0fe1c7 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 13 Sep 2016 13:18:38 +0200 +Subject: [PATCH] 40-redhat.rules: don't hoplug memory on s390x + +Resolves: #1370161 +--- + rules/40-redhat.rules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules +index 3335fe5..4c56950 100644 +--- a/rules/40-redhat.rules ++++ b/rules/40-redhat.rules +@@ -4,7 +4,7 @@ + SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1" + + # Memory hotadd request +-SUBSYSTEM=="memory", ACTION=="add", ATTR{state}=="offline", ATTR{state}="online" ++SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/usr/bin/systemd-detect-virt", RESULT!="zvm", ATTR{state}=="offline", ATTR{state}="online" + + # reload sysctl.conf / sysctl.conf.d settings when the bridge module is loaded + ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge" diff --git a/SOURCES/org.freedesktop.hostname1.policy b/SOURCES/org.freedesktop.hostname1.policy new file mode 100644 index 0000000..0014156 --- /dev/null +++ b/SOURCES/org.freedesktop.hostname1.policy @@ -0,0 +1,100 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Set host name + Rechnername festlegen + Ορισμός ονόματος οικοδεσπότη + Définir le nom d'hôte + Gépnév beállítása + Configura il nome host + Ustawienie nazwy komputera + Definir nome de máquina + Настроить имя компьютера + Ange värdnamn + Встановити назву вузла + Authentication is required to set the local host name. + Legitimierung ist zum Festlegen des lokalen Rechnernamens notwendig + Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη. + Authentification requise pour définir le nom d'hôte local. + Hitelesítés szükséges a helyi gépnév beállításához. + Autenticazione richiesta per configurare il nome host locale. + Wymagane jest uwierzytelnienie, aby ustawić nazwę lokalnego komputera. + É necessária autenticação para definir nome de máquina local. + Чтобы настроить имя компьютера, необходимо пройти аутентификацию. + Autentisering krävs för att ange lokalt värdnamn. + Засвідчення потрібне, щоб встановити назву локального вузла. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Set static host name + Statischen Rechnernamen festlegen + Ορισμός στατικού ονόματος οικοδεσπότη + Définir le nom d'hôte statique + Statikus gépnév beállítása + Configura il nome host statico + Ustawienie statycznej nazwy komputera + Definir nome estático de máquina + Настроить статическое имя компьютера + Ange statiskt värdnamn + Встановити статичну назву вузла + Authentication is required to set the statically configured local host name, as well as the pretty host name. + Authentifizierung ist erforderlich, um den statisch geänderten, lokalen Rechnernamen, sowie den beschönigten Rechnernamen festzulegen. + Απαιτείται πιστοποίηση για να ορίσετε το στατικά ρυθμισμένο όνομα τοπικού οικοδεσπότη, καθώς και το pretty όνομα οικοδεσπότη. + Authentification requise pour définir le nom d'hôte local de manière statique, tout comme le nom d'hôte familier. + Hitelesítés szükséges a statikusan megadott helyi gépnév, valamint a szép gépnév beállításához. + Autenticazione richiesta per configurare staticamente il nome host locale e il nome host descrittivo. + Wymagane jest uwierzytelnienie, aby ustawić statycznie skonfigurowaną nazwę lokalnego komputera, a także jego ładną nazwę. + É necessária autenticação para definir o nome de máquina local configurado estaticamente, assim como o nome apresentável de máquina. + Чтобы настроить статическое имя компьютера, а также его «красивое» имя, необходимо пройти аутентификацию. + Autentisering krävs för att ange det statiskt konfigurerade lokala värdnamnet såväl som det stiliga värdnamnet. + Засвідчення потрібне, щоб вказати статично налаштовану назву локального вузла, так само й форматовану. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.hostname1.set-hostname org.freedesktop.hostname1.set-machine-info + + + + Set machine information + Maschinen-Information festlegen + Ορισμός πληροφοριών μηχανής + Définir les informations sur la machine + Gépinformációk beállítása + Configura le informazioni sulla macchina + Ustawienie informacji o komputerze + Definir informações da máquina + Настроить информацию о компьютере + Ange datorinformation + Встановити інформацію про машину + Authentication is required to set local machine information. + Legitimierung ist zum Festlegen der lokalen Maschinen-Information erforderlich. + Απαιτείται πιστοποίηση για να ορίσετε πληροφορίες τοπικής μηχανής. + Authentification requise pour définir les informations sur la machine locale. + Hitelesítés szükséges a helyi gép információinak beállításához. + Autenticazione richiesta per configurare le informazioni sulla macchina locale. + Wymagane jest uwierzytelnienie, aby ustawić informacje o lokalnym komputerze. + É necessária autenticação para definir informações de máquina local. + Чтобы настроить информацию о компьютере, необходимо пройти аутентификацию. + Autentisering krävs för att ange lokal datorinformation. + Засвідчення потрібно, щоб вказати локальну інформацію про машини. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.import1.policy b/SOURCES/org.freedesktop.import1.policy new file mode 100644 index 0000000..e05e4bb --- /dev/null +++ b/SOURCES/org.freedesktop.import1.policy @@ -0,0 +1,27 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Download a VM or container image + Abbild einer VM oder eines Containers herunterladen + Télécharger une image de machine virtuelle (VM) ou de conteneur + Pobranie obrazu maszyny wirtualnej lub kontenera + Загрузить образ виртуальной машины или контейнера + Authentication is required to download a VM or container image + Legitimierung ist zum Herunterladen eines VM- oder Containerabbilds erforderlich + Authentification requise pour télécharger une image de machine virtuelle (VM) ou de conteneur. + Wymagane jest uwierzytelnienie, aby pobrać obraz maszyny wirtualnej lub kontenera + Чтобы загрузить образ виртуальной машины или контейнера, необходимо пройти аутентификацию. + + auth_admin + auth_admin + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.locale1.policy b/SOURCES/org.freedesktop.locale1.policy new file mode 100644 index 0000000..5f9b571 --- /dev/null +++ b/SOURCES/org.freedesktop.locale1.policy @@ -0,0 +1,70 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Set system locale + Die lokale Sprachumgebung festlegen + Ορισμός τοπικών ρυθμίσεων συστήματος + Définir la langue du système + Területi beállítás megadása + Configura le impostazioni regionali di sistema + Ustawienie lokalizacji systemu + Definir configurações regionais do sistema + Настроить системную локаль + Ange systemlokal + Вказати системну локаль + Authentication is required to set the system locale. + Legitimierung ist zum Festlegen der systemweiten Spracheinstellungen erforderlich. + Απαιτείται πιστοποίηση για να ορίσετε τις τοπικές ρυθμίσεις του συστήματος. + Authentification requise pour définir la langue du système. + Hitelesítés szükséges a rendszer területi beállításainak megadásához. + Autenticazione richiesta per configurare le impostazioni regionali di sistema. + Wymagane jest uwierzytelnienie, aby ustawić lokalizację systemu. + É necessária autenticação para definir as configurações regionais do sistema. + Чтобы настроить системную локаль, необходимо пройти аутентификацию. + Autentisering krävs för att ange systemlokal. + Засвідчення потрібно, щоб встановити системну локаль. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.locale1.set-keyboard + + + + Set system keyboard settings + Tastatureinstellungen des Systems festlegen + Ορισμός ρυθμίσεων πληκτρολογίου συστήματος + Définir les paramètres de clavier du système + Rendszer billentyűzetbeállítások megadása + Configura la tastiera di sistema + Ustawienie klawiatury systemu + Definir configurações de teclado do sistema + Настроить параметры клавиатуры + Ange systeminställningar för tangentbord + Вказати налаштування системної клавіатури + Authentication is required to set the system keyboard settings. + Legitimierung ist zum Festlegen der Tastatureinstellungen des Systems erforderlich. + Απαιτείται πιστοποίηση για να ορίσετε τις ρυθμίσεις πληκτρολογίου του συστήματος. + Authentification requise pour définir les paramètres de clavier du système. + Hitelesítés szükséges a rendszer billentyűzetbeállításainak megadásához. + Autenticazione richiesta per configurare la tastiera di sistema. + Wymagane jest uwierzytelnienie, aby ustawić klawiaturę systemu. + É necessária autenticação para definir as configurações de teclado do sistema. + Чтобы настроить параметры клавиатуры, необходимо пройти аутентификацию. + Autentisering krävs för att ange systeminställningar för tangentbord. + Засвідчення потрібно, щоб вказати налаштування системної клавіатури. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.login1.policy b/SOURCES/org.freedesktop.login1.policy new file mode 100644 index 0000000..0a19273 --- /dev/null +++ b/SOURCES/org.freedesktop.login1.policy @@ -0,0 +1,743 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Allow applications to inhibit system shutdown + Anwendungen dürfen das Herunterfahren des Systems unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τον τερματισμό του συστήματος + Permet aux applications d'empêcher l'arrêt du système + Alkalmazások meggátolhatják a rendszer leállítását + Consenti alle applicazioni di inibire lo spegnimento del sistema + Zezwolenie programom na wstrzymywanie wyłączenia systemu + Permitir que aplicativos inibam o desligamento do sistema + Разрешить приложениям устанавливать блокировку на выключение системы + Tillåt program att hindra systemavstängning + Дозволити програмам перешкоджати вимкненню системи + Authentication is required for an application to inhibit system shutdown. + Legitimierung ist notwendig, um Anwendungen das Herunterfahren des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει τον τερματισμό του συστήματος. + Authentification requise pour permettre à une application d'empêcher l'arrêt du système. + Hitelesítés szükséges egy alkalmazás számára a rendszerleállítás meggátlásához. + Autenticazione richiesta per un'applicazione per inibire lo spegnimento del sistema. + Program wymaga uwierzytelnienia, aby wstrzymać wyłączenie systemu. + É necessária autenticação para que um aplicativo iniba o desligamento do sistema. + Чтобы разрешить приложениям устанавливать блокировку на выключение системы, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemavstängning. + Засвідчення потрібно, щоб дозволити програмам перешкоджати вимкненню системи. + + no + yes + yes + + org.freedesktop.login1.inhibit-delay-shutdown org.freedesktop.login1.inhibit-block-sleep org.freedesktop.login1.inhibit-delay-sleep org.freedesktop.login1.inhibit-block-idle + + + + Allow applications to delay system shutdown + Anwendungen dürfen das Herunterfahren des Systems verzögern + Να επιτρέπεται στις εφαρμογές να καθυστερούν τον τερματισμό του συστήματος + Permet aux applications de retarder l'arrêt du système + Alkalmazások késleltethetik a rendszer leállítását + Consenti alle applicazioni di ritardare lo spegnimento del sistema + Zezwolenie programom na opóźnienie wyłączenia systemu + Permitir que aplicativos atrasem o desligamento do sistema + Разрешить приложениям устанавливать задержку на выключение системы + Tillåt program att fördröja systemavstängning + Дозволити програмам затримувати вимкнення системи + Authentication is required for an application to delay system shutdown. + Legitimierung ist notwendig, um Anwendungen das Verzögern des Herunterfahren des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να καθυστερήσει τον τερματισμό του συστήματος. + Authentification requise pour permettre à une application de retarder l'arrêt du système. + Hitelesítés szükséges egy alkalmazás számára a rendszerleállítás késleltetéséhez. + Autenticazione richiesta per un'applicazione per ritardare lo spegnimento del sistema. + Program wymaga uwierzytelnienia, aby opóźnić wyłączenie systemu. + É necessária autenticação para que um aplicativo atrase o desligamento do sistema. + Чтобы разрешить приложениям устанавливать задержку на выключение системы, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att fördröja systemavstängning. + Засвідчення потрібно, щоб дозволити програмам затримувати вимкнення системи. + + yes + yes + yes + + org.freedesktop.login1.inhibit-delay-sleep + + + + Allow applications to inhibit system sleep + Anwendungen dürfen den Bereitschaftsmodus unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν την ύπνωση του συστήματος + Permet aux applications d'empêcher la mise en veille du système + Alkalmazások meggátolhatják a rendszer altatását + Consenti alle applicazioni di inibire il sistema in pausa + Zezwolenie programom na wstrzymanie uśpienia systemu + Permitir que aplicativos inibam a suspensão do sistema + Разрешить приложениям устанавливать блокировку на засыпание системы + Tillåt program att hindra system att försättas i viloläge + Дозволити програмам перешкоджати засинанню системи + Authentication is required for an application to inhibit system sleep. + Legitimierung ist erforderlich, um Anwendungen das Unterbinden des Bereitschaftsmodus zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την ύπνωση του συστήματος. + Authentification requise pour permettre à une application d'empêcher la mise en veille du système. + Hitelesítés szükséges egy alkalmazás számára a rendszeraltatás meggátlásához. + Autenticazione richiesta per un'applicazione per inibire il sistema in pausa. + Program wymaga uwierzytelnienia, aby wstrzymać uśpienie systemu. + É necessária autenticação para que um aplicativo iniba a suspensão do sistema. + Чтобы разрешить приложениям устанавливать блокировку на засыпание системы, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra ett system att försättas i viloläge. + Засвідчення потрібно, щоб дозволити програмам перешкоджати засинанню системи. + + no + yes + yes + + org.freedesktop.login1.inhibit-delay-sleep org.freedesktop.login1.inhibit-block-idle + + + + Allow applications to delay system sleep + Anwendungen dürfen den Bereitschaftsmodus verzögern + Να επιτρέπεται στις εφαρμογές να καθυστερούν την ύπνωση του συστήματος + Permet aux applications de retarder la mise en veille du système + Alkalmazások késleltethetik a rendszer altatását + Consenti alle applicazioni di ritardare il sistema in pausa + Zezwolenie programom na opóźnienie uśpienia systemu + Permite que aplicativos atrasem a suspensão do sistema + Разрешить приложениям устанавливать задержку на засыпание системы + Tillåt program att fördröja att system försätts i viloläge + Дозволити програмами затримувати засинання системи + Authentication is required for an application to delay system sleep. + Legitimierung ist erforderlich, um Anwendungen das Verzögern des Bereitschaftsmodus zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να καθυστερήσει την ύπνωση του συστήματος. + Authentification requise pour permettre à une application de retarder la mise en veille du système. + Hitelesítés szükséges egy alkalmazás számára a rendszeraltatás késleltetéséhez. + Autenticazione richiesta per un'applicazione per ritardare il sistema in pausa. + Program wymaga uwierzytelnienia, aby opóźnić uśpienie systemu. + É necessária autenticação para que um aplicativo atrase a suspensão do sistema. + Чтобы разрешить приложениям устанавливать задержку на засыпание системы, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att fördröja ett system att försättas i viloläge. + Засвідчення потрібно, щоб дозволити програмам затримувати засинання системи. + + yes + yes + yes + + + + + Allow applications to inhibit automatic system suspend + Anwendungen dürfen den automatischen Bereitschaftsmodus unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν την αυτόματη αναστολή του συστήματος + Permet aux applications d'empêcher l'hibernation automatique du système + Alkalmazások meggátolhatják a rendszer automatikus felfüggesztését + Consenti alle applicazioni di inibire la sospesione automatica del sistema + Zezwolenie programom na wstrzymanie automatycznego uśpienia systemu + Permitir que aplicativos inibam a suspensão automática do sistema + Разрешить приложениям устанавливать блокировку на автоматический переход системы в ждущий режим + Tillåt program att hindra automatiskt systemvänteläge + Дозволити програмам перешкоджати автоматичному призупиненню системи + Authentication is required for an application to inhibit automatic system suspend. + Legitimierung ist notwendig, um Anwendungen das Unterbinden des automatischen Bereitschaftsmodus zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την αυτόματη αναστολή του συστήματος. + Authentification requise pour permettre à une application d'empêcher l'hibernation automatique du système. + Hitelesítés szükséges egy alkalmazás számára az automatikus rendszerfelfüggesztés meggátlásához. + Autenticazione richiesta per un'applicazione per inibire la sospensione automatica del sistema. + Program wymaga uwierzytelnienia, aby wstrzymać automatyczne uśpienie systemu. + É necessária autenticação para que um aplicativo iniba a suspensão automática do sistema. + Чтобы разрешить приложениям устанавливать блокировку на автоматический переход системы в ждущий режим, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra automatiskt systemvänteläge. + Засвідчення потрібно, щоб дозволити програмам перешкоджати автоматичному призупиненню системи. + + yes + yes + yes + + + + + Allow applications to inhibit system handling of the power key + Anwendungen dürfen das Auswerten des Ein-/Ausschaltknopfs des Systems unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του πλήκτρου ενεργοποίησης του συστήματος + Permet aux applications d'empêcher la gestion du bouton d'alimentation du système + Alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését + Consenti alle applicazioni di inibire la gestione di sistema del tasto di accensione + Zezwolenie programom na wstrzymanie obsługi klawisza zasilania przez system + Permitir que aplicativos inibam o sistema de gerenciar o botão de energia + Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку выключения + Tillåt program att hindra systemhantering av strömknappen + Дозволити програмам перешкоджати обробленню системою клавіші живлення + Authentication is required for an application to inhibit system handling of the power key. + Legitmierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung der Ein-/Ausschaltknopfs des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την διαχείριση του πλήκτρου ενεργοποίησης του συστήματος. + Authentification requise pour permettre à une application d'empêcher la gestion du bouton d'alimentation du système. + Hitelesítés szükséges egy alkalmazás számára a bekapcsoló gomb rendszer általi kezelésének meggátlásához. + Autenticazione richiesta per un'applicazione per inibire la gestione di sistema del tasto di accensione. + Program wymaga uwierzytelnienia, aby wstrzymać obsługę klawisza zasilania przez system. + É necessária autenticação para que um aplicativo iniba a manipulação do sistema sobre a chave de ligar/desligar. + Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку выключения, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemhantering av strömknappen. + Засвідчення потрібно, щоб дозволити програмам перешкоджати обробленню системою клавіші живлення. + + no + yes + yes + + org.freedesktop.login1.inhibit-handle-suspend-key org.freedesktop.login1.inhibit-handle-hibernate-key org.freedesktop.login1.inhibit-handle-lid-switch + + + + Allow applications to inhibit system handling of the suspend key + Anwendungen dürfen das Auswerten des Bereitschaftsknopfs des Systems unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του πλήκτρου αναστολής του συστήματος. + Permet aux applications d'empêcher la gestion du bouton de mise en veille du système + Alkalmazások meggátolhatják a felfüggesztés gomb rendszer általi kezelését + Consenti alle applicazioni di inibire la gestione di sistema del tasto di sospensione + Zezwolenie programom na wstrzymanie obsługi klawisza uśpienia przez system + Permitir que aplicativos inibam o sistema de gerenciar o botão de suspensão + Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в ждущий режим + Tillåt program att hindra systemhantering av väntelägesknappen + Дозволити програмам перешкоджати обробленню системою клавіші призупинення + Authentication is required for an application to inhibit system handling of the suspend key. + Legitimierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung des Bereitschaftsknopfes des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την διαχείριση του πλήκτρου αναστολής του συστήματος. + Authentification requise pour permettre à une application d'empêcher la gestion du bouton de mise en veille du système. + Hitelesítés szükséges egy alkalmazás számára a felfüggesztés gomb rendszer általi kezelésének meggátlásához. + Autenticazione richiesta per un'applicazione per inibire la gestione di sistema del tasto di sospensione. + Program wymaga uwierzytelnienia, aby wstrzymać obsługę klawisza uśpienia przez system. + É necessária autenticação para que um aplicativo iniba a manipulação do sistema sobre a chave de suspensão. + Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в ждущий режим, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemhantering av väntelägesknappen. + Засвідчення потрібно, щоб дозволити програмам перешкоджати обробленню системою клавіші призупинення. + + no + yes + yes + + org.freedesktop.login1.inhibit-handle-hibernate-key org.freedesktop.login1.inhibit-handle-lid-switch + + + + Allow applications to inhibit system handling of the hibernate key + Anwendungen dürfen das Auswerten des Knopfs für den Ruhezustand unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του πλήκτρου αδρανοποίησης του συστήματος + Permet aux applications d'empêcher la gestion du bouton d'hibernation du système + Alkalmazások meggátolhatják a hibernálás gomb rendszer általi kezelését + Consenti alle applicazioni di inibire la gestione di sistema del tasto di ibernazione + Zezwolenie programom na wstrzymanie obsługi klawisza hibernacji przez system + Permitir que aplicativos inibam o sistema de gerenciar o botão de hibernação + Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в спящий режим + Tillåt program att hindra systemhantering av vilolägesknappen + Дозволити програмам перешкоджати обробленню системою клавіші присипання + Authentication is required for an application to inhibit system handling of the hibernate key. + Legitimierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung des Knopfs für den Ruhezustand zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την διαχείριση του πλήκτρου αδρανοποίησης του συστήματος. + Authentification requise pour permettre à une application d'empêcher la gestion du bouton d'hibernation du système. + Hitelesítés szükséges egy alkalmazás számára a hibernálás gomb rendszer általi kezelésének meggátlásához. + Autenticazione richiesta per un'applicazione per inibire la gestione di sistema del tasto di ibernazione. + Program wymaga uwierzytelnienia, aby wstrzymać obsługę klawisza hibernacji przez system. + É necessária autenticação para que um aplicativo iniba a manipulação do sistema sobre a chave de hibernar. + Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на кнопку перехода в спящий режим, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemhantering av vilolägesknappen. + Засвідчення потрібно, щоб дозволити програмам перешкоджати обробленню системою клавіші присипання. + + no + yes + yes + + + + + Allow applications to inhibit system handling of the lid switch + Anwendungen dürfen das Auswerten des Notebookdeckelschalters unterbinden + Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του διακόπτη καλύμματος του συστήματος + Permet aux applications d'empêcher la gestion par le système du rabat de l'écran + Alkalmazások meggátolhatják a fedélkapcsoló rendszer általi kezelését + Consenti alle applicazioni di inibire la gestione di sistema alla apertura/chiusura del portatile + Zezwolenie programom na wstrzymanie obsługi przełącznika pokrywy przez system + Permitir que aplicativos inibam o sistema de gerenciar a abertura/fechamento da tampa do dispositivo portátil + Разрешить приложениям устанавливать блокировку на обработку закрытия крышки ноутбука + Tillåt program att hindra systemhantering av växel för datorhölje + Дозволити програмам перешкоджати обробленню системою клавіші перемикання кришки + Authentication is required for an application to inhibit system handling of the lid switch. + Legitimierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung des Notebookdeckelschalters des Systems zu erlauben. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την διαχείριση του διακόπτη καλύμματος του συστήματος. + Authentification requise pour permettre à une application d'empêcher la gestion par le système du rabat de l'écran. + Hitelesítés szükséges egy alkalmazás számára a fedélkapcsoló rendszer általi kezelésének meggátlásához. + Autenticazione richiesta per consentire ad un'applicazione di inibire la gestione di sistema alla apertura/chiusura del portatile. + Program wymaga uwierzytelnienia, aby wstrzymać obsługę przełącznika pokrywy przez system. + É necessária autenticação para que um aplicativo iniba a manipulação do sistema sobre o interruptor da tela. + Чтобы разрешить приложениям устанавливать блокировку на обработку закрытия крышки ноутбука, необходимо пройти аутентификацию. + Autentisering krävs för att tillåta ett program att hindra systemhantering av brytaren för datorhöljet. + Засвідчення потрібно, щоб дозволити програмам перешкоджати обробленню системою клавіші перемикання кришки. + + no + yes + yes + + + + + Allow non-logged-in users to run programs + Nicht angemeldete Benutzer dürfen Programme ausführen + Να επιτρέπεται σε μη συνδεμένους χρήστες να εκτελούν προγράμματα + Permet aux utilisateurs non connectés d'exécuter des programmes + Programfuttatás engedélyezése be nem jelentkezett felhasználók számára + Consenti agli utenti non connessi di eseguire programmi + Zezwolenie niezalogowanym użytkownikom na uruchamianie programów + Permitir que programas sejam executados por usuários que não possuem sessão + Разрешить пользователям оставлять программы в фоновом режиме после завершения сеанса + Tillåt ej inloggade användare att köra program + Дозволити незареєстрованим користувачам запускати програми + Authentication is required to run programs as a non-logged-in user. + Legitimierung ist erforderlich, damit nicht angemeldete Benutzer Programme ausführen dürfen. + Απαιτείται πιστοποίηση για να επιτρέπεται σε μη συνδεμένους χρήστες να εκτελούν προγράμματα. + Authentification requise pour permettre aux utilisateurs non connectés d'exécuter des programmes. + Hitelesítés szükséges a programfuttatáshoz be nem jelentkezett felhasználóként. + Autenticazione richiesta per consentire agli utenti non connessi di eseguire programmi. + Wymagane jest uwierzytelnienie, aby uruchamiać programy jako niezalogowany użytkownik. + É necessária autenticação para executar programas como usuário sem sessão aberta. + Чтобы разрешить пользователям оставлять программы в фоновом режиме после завершения сеанса, необходимо пройти аутентификацию. + Autentisering krävs för att köra program som en icke inloggad användare. + Засвідчення потрібно, щоб дозволити незареєстрованим користувачам запускати програми. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Allow attaching devices to seats + Das Anschließen von Geräten an Arbeitsstationen erlauben + Να επιτρέπεται η προσάρτηση συσκευών στους σταθμούς εργασίας + Permet d'associer des périphériques à des postes (seats) + Eszközök csatolásának engedélyezése munkaállomásokhoz + Consenti di collegare dispositivi alle postazioni + Zezwolenie na podłączanie urządzeń do stanowisk + Permitir conectar dispositivos em estações + Разрешить подключение устройств к рабочим местам + Tillåt att binda enheter till platser + Дозволити під'єднання пристроїв до місць + Authentication is required for attaching a device to a seat. + Legitimierung ist zum Anschließen eines Geräts an eine Arbeitsstation notwendig. + Απαιτείται πιστοποίηση για προσάρτηση μιας συσκευής σε έναν σταθμό εργασίας. + Authentification requise pour associer un périphérique à un poste (seat). + Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy munkaállomáshoz + Autenticazione richiesta per collegare un dispositivo ad una postazione. + Wymagane jest uwierzytelnienie, aby podłączyć urządzenie do stanowiska. + É necessária autenticação para conectar um dispositivo em uma estação. + Чтобы разрешить подключение устройств к рабочим местам, необходимо пройти аутентификацию. + Autentisering krävs för att binda en enhet till en plats. + Засвідчення потрібно, щоб під'єднувати пристрої до місць. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.flush-devices + + + + Flush device to seat attachments + Zurücksetzen der an eine Arbeitsstation angeschlossenen Geräte + Αφαίρεση συσκευής από προσαρτήσεις σταθμού εργασίας + Révoquer les associations de périphériques aux postes (seats) + Eszközök és munkaállomások csatolásainak törlése + Scollega i dispositivi dalla postazione + Usunięcie podłączenia urządzeń do stanowisk + Liberar dispositivo para conexões da estação + Сбросить привязки устройств к рабочим местам + Töm bindningar för enhet-till-plats + Очисний пристрій для під'єднань до місця + Authentication is required for resetting how devices are attached to seats. + Legitimierung ist zum Zurücksetzen notwendig, wie Geräte an eine Arbeitsstation angeschlossen werden. + Απαιτείται πιστοποίηση για επαναφορά του τρόπου που οι συσκευές προσαρτώνται στους σταθμούς εργασίας. + Authentification requise pour révoquer les associations de périphériques aux postes (seats). + Hitelesítés szükséges az eszközök munkaállomásokhoz csatolásainak alaphelyzetbe állításához. + Autenticazione richiesta per ripristinare come i dispositivi sono collegati alle postazioni. + Wymagane jest uwierzytelnienie, aby ponownie ustawić sposób podłączenia urządzeń do stanowisk. + É necessária autenticação para redefinir a quantidade de dispositivos conectados na estação. + Чтобы сбросить привязки устройств к рабочим местам, необходимо пройти аутентификацию. + Autentisering krävs för att återställa hur enheter är bundna till platser. + Засвідчення потрібно, щоб перезапустити спосіб під'єднання до місць. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Power off the system + Das System ausschalten + Σβήσιμο του συστήματος + Éteindre le système + A rendszer kikapcsolása + Spegnere il sistema + Wyłączenie systemu + Desligar o sistema + Выключить систему + Stäng av systemet + Вимкнути систему + Authentication is required for powering off the system. + Legitimierung ist zum Ausschalten des Systems notwendig. + Απαιτείται πιστοποίηση για την σβήσιμο του συστήματος. + Authentification requise pour éteindre le système. + Hitelesítés szükséges a rendszer kikapcsolásához. + Autenticazione richiesta per spegnere il sistema. + Wymagane jest uwierzytelnienie, aby wyłączyć system. + É necessária autenticação para desligar o sistema. + Чтобы выключить систему, необходимо пройти аутентификацию. + Autentisering krävs för att stänga av systemet. + Засвідчення потрібно, щоб вимкнути систему. + + auth_admin_keep + auth_admin_keep + yes + + + + + Power off the system while other users are logged in + Das System herunter fahren, während andere Benutzer angemeldet sind + Σβήσιμο του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι + Éteindre le système alors que d'autres utilisateurs sont connectés + A rendszer kikapcsolása miközben be vannak jelentkezve más felhasználók + Spegnere il sistema mentre altri utenti sono connessi + Wyłączenie systemu, kiedy są zalogowani inni użytkownicy + Desligar o sistema enquanto outros usuários estão conectados + Выключить систему, несмотря на то, что в ней работают другие пользователи + Stäng av systemet medan andra användare är inloggade + Вимикнути систему, коли інші користувачі ще в ній + Authentication is required for powering off the system while other users are logged in. + Legitimierung ist zum Herunterfahren des Systems notwendig, während andere Benutzer angemeldet sind. + Απαιτείται πιστοποίηση για σβήσιμο του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι. + Authentification requise pour éteindre le système alors que d'autres utilisateurs sont connectés. + Hitelesítés szükséges a rendszer kikapcsolásához miközben be vannak jelentkezve más felhasználók. + Autenticazione richiesta per spegnere il sistema mentre altri utenti sono connessi. + Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy są zalogowani inni użytkownicy. + É necessária autenticação para desligar o sistema enquanto outros usuários estão conectados. + Чтобы выключить систему, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию. + Autentisering krävs för att stänga av systemet medan andra användare är inloggade. + Засвідчення потрібно, щоб вимкнути систему, коли інші користувачі в ній. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.power-off + + + + Power off the system while an application asked to inhibit it + Das System ausschalten, während eine Anwendung anfordert es zu unterbinden + Απενεργοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Éteindre le système alors qu'une application a demandé de l'empêcher + A rendszer kikapcsolása miközben egy alkalmazás ennek meggátlását kérte + Spegnere il sistema mentre un'applicazione chiede di inibirne l'azione + Wyłączenie systemu, kiedy program zażądał jego wstrzymania + Desligar o sistema enquanto um aplicativo solicitou inibição + Выключить систему, несмотря на то, что приложение запросило блокировку выключения + Stäng av systemet även då ett program hindrar det + Вимкнути систему, коли програми намагаються першкодити цьому + Authentication is required for powering off the system while an application asked to inhibit it. + Legitimierung ist zum Ausschalten des Systems notwendig, während eine Anwendung anfordert es zu unterbinden. + Απαιτείται πιστοποίηση για απενεργοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Authentification requise pour éteindre le système alors qu'une application a demandé de l'empêcher. + Hitelesítés szükséges a rendszer kikapcsolásához miközben egy alkalmazás ennek meggátlását kérte. + Autenticazione richiesta per spegnere il sistema mentre un'applicazione chiede di inibirne l'azione. + Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy program zażądał jego wstrzymania. + É necessária autenticação para desligar o sistema enquanto um aplicativo solicitou inibição. + Чтобы выключить систему, несмотря на то, что приложение запросило блокировку выключения, необходимо пройти аутентификацию. + Autentisering krävs för att stänga av systemet även då ett program hindrar det. + Засвідчення потрібно, щоб вимкнути систему, коли програми намагаються першкодити цьому. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.power-off + + + + Reboot the system + Das System neu starten + Επανεκκίνηση του συστήματος + Redémarrer le système + A rendszer újraindítása + Riavviare il sistema + Ponowne uruchomienie systemu + Reiniciar o sistema + Перезагрузить систему + Starta om systemet + Перезавантажити систему + Authentication is required for rebooting the system. + Legitimierung ist zum Neustart des Systems notwendig. + Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος. + Authentification requise pour redémarrer le système. + Hitelesítés szükséges a rendszer újraindításához. + Autenticazione richiesta per riavviare il sistema. + Wymagane jest uwierzytelnienie, aby ponownie uruchomić system. + É necessária autenticação para reiniciar o sistema. + Чтобы перезагрузить систему, необходимо пройти аутентификацию. + Autentisering krävs för att starta om systemet. + Для перезавантаження системи необхідна ідентифікація. + + auth_admin_keep + auth_admin_keep + yes + + + + + Reboot the system while other users are logged in + Das Systems neu starten, während andere Benutzer angemeldet sind + Επανεκκίνηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι + Redémarrer le système alors que d'autres utilisateurs sont connectés + A rendszer újraindítása mialatt be vannak jelentkezve más felhasználók + Riavviare il sistema mentre altri utenti sono connessi + Ponowne uruchomienie systemu, kiedy są zalogowani inni użytkownicy + Reiniciar o sistema enquanto outros usuários estiverem conectados + Перезагрузить систему, несмотря на то, что в ней работают другие пользователи + Starta om systemet medan andra användare är inloggade + Перезавантажити, якщо інщі користувачі в системі + Authentication is required for rebooting the system while other users are logged in. + Legitimierung ist zum Neustart des Systems notwendig, während andere Benutzer angemeldet sind. + Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι. + Authentification requise pour redémarrer le système alors que d'autres utilisateurs sont connectés. + Hitelesítés szükséges a rendszer újraindításához miközben be vannak jelentkezve más felhasználók. + Autenticazione richiesta per riavviare il sistema mentre altri utenti sono connessi. + Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy są zalogowani inni użytkownicy. + É necessária autenticação para reiniciar o sistema enquanto outros usuários estiverem conectados. + Чтобы перезагрузить систему, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию. + Autentisering krävs för att starta om systemet medan andra användare är inloggade. + Засвідчення потрібно, щоб перезапустити систему, коли інші користувачі в ній. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.reboot + + + + Reboot the system while an application asked to inhibit it + Das System neu starten, während eine Anwendung anfordert es zu unterbinden + Επανεκκίνηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί + Redémarrer le système alors qu'une application a demandé de l'empêcher + A rendszer újraindítása miközben egy alkalmazás ennek meggátlását kérte + Riavviare il sistema mentre un'applicazione chiede di inibirne l'azione + Ponowne uruchomienie systemu, kiedy program zażądał jego wstrzymania + Reiniciar o sistema enquanto um aplicativo solicitou inibição + Перезагрузить систему, несмотря на то, что приложение запросило блокировку выключения + Starta om systemet även då ett program hindrar det. + Перезапустити систему, коли програми намагаються першкодити цьому + Authentication is required for rebooting the system while an application asked to inhibit it. + Legitimierung ist zum Neustart des Systems notwendig, während eine Anwendung anforderte es zu unterbinden. + Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Authentification requise pour redémarrer le système alors qu'une application a demandé de l'empêcher. + Hitelesítés szükséges a rendszer újraindításához miközben egy alkalmazás ennek meggátlását kérte. + Autenticazione richiesta per riavviare il sistema mentre un'applicazione chiede di inibirne l'azione. + Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy program zażądał jego wstrzymania. + É necessária autenticação para reiniciar o sistema enquanto um aplicativo solicitou inibição. + Чтобы перезагрузить систему, несмотря на то, что приложение запросило блокировку выключения, необходимо пройти аутентификацию. + Autentisering krävs för att starta om systemet även då ett program hindrar det. + Засвідчення потрібно, щоб перезапустити систему, коли програми намагаються першкодити цьому. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.reboot + + + + Suspend the system + Das System in Bereitschaft versetzen + Αναστολή του συστήματος + Mettre le système en veille + A rendszer felfüggesztése + Sospendere il sistema + Uśpienie systemu + Suspender o sistema + Перевести систему в ждущий режим + Försätt system i vänteläge + Призупинити систему + Authentication is required for suspending the system. + Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig. + Απαιτείται πιστοποίηση για την αναστολή του συστήματος. + Authentification requise pour mettre le système en veille. + Hitelesítés szükséges a rendszer felfüggesztéséhez. + Autenticazione richiesta per sospendere il sistema. + Wymagane jest uwierzytelnienie, aby uśpić system. + É necessária autenticação para suspender o sistema. + Чтобы перевести систему в ждущий режим, необходимо пройти аутентификацию. + Autentisering krävs för att försätta system i vänteläge. + Засвідчення потрібно, щоб призупинити систему. + + auth_admin_keep + auth_admin_keep + yes + + + + + Suspend the system while other users are logged in + Das System in Bereitschaft versetzen, während andere Benutzer angemeldet sind. + Αναστολή του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι + Mettre le système en veille alors que d'autres utilisateurs sont connectés + A rendszer felfüggesztése mialatt be vannak jelentkezve más felhasználók + Sospendere il sistema mentre altri utenti sono connessi + Uśpienie systemu, kiedy są zalogowani inni użytkownicy + Suspender o sistema enquanto outros usuários estiverem conectados + Перевести систему в ждущий режим, несмотря на то, что в ней работают другие пользователи + Försätt systemet i vänteläge medan andra användare är inloggade + Призупинити систему, коли інші користувачі в ній + Authentication is required for suspending the system while other users are logged in. + Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig, während andere Benutzer angemeldet sind. + Απαιτείται πιστοποίηση για αναστολή του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι. + Authentification requise pour mettre le système en veille alors que d'autres utilisateurs sont connectés. + Hitelesítés szükséges a rendszer felfüggesztéséhez miközben be vannak jelentkezve más felhasználók. + Autenticazione richiesta per sospendere il sistema mentre altri utenti sono connessi. + Wymagane jest uwierzytelnienie, aby uśpić system, kiedy są zalogowani inni użytkownicy. + É necessária autenticação para suspender o sistema enquanto outros usuários estiverem conectados. + Чтобы перевести систему в ждущий режим, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию. + Autentisering krävs för att försätta systemet i vänteläge medan andra användare är inloggade. + Засвідчення потрібно, щоб призупинити систему, коли інші користувачі в ній. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.suspend + + + + Suspend the system while an application asked to inhibit it + Das System in Bereitschaft versetzen, während eine Anwendung anfordert dies zu unterbinden + Αναστολή του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί + Mettre le système en veille alors qu'une application a demandé de l'empêcher + A rendszer felfüggesztése miközben egy alkalmazás ennek meggátlását kérte + Sospendere il sistema mentre un'applicazione chiede di inibirne l'azione + Uśpienie systemu, kiedy program zażądał jego wstrzymania + Suspender o sistema enquanto um aplicativo solicitou inibição + Перевести систему в ждущий режим, несмотря на то, что приложение запросило блокировку + Försätt systemet i vänteläge även då ett program hindrar det + Призупинити систему, коли програми намагаються першкодити цьому + Authentication is required for suspending the system while an application asked to inhibit it. + Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig, während eine Anwendung anfordert dies zu unterbinden. + Απαιτείται πιστοποίηση για αναστολή του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Authentification requise pour mettre le système en veille alors qu'une application a demandé de l'empêcher. + Hitelesítés szükséges a rendszer felfüggesztéséhez miközben egy alkalmazás ennek meggátlását kérte. + Autenticazione richiesta per sospendere il sistema mentre un'applicazione chiede di inibirne l'azione. + Wymagane jest uwierzytelnienie, aby uśpić system, kiedy program zażądał jego wstrzymania. + É necessária autenticação para suspender o sistema enquanto um aplicativo solicitou inibição. + Чтобы перевести систему в ждущий режим, несмотря на то, что приложение запросило блокировку, необходимо пройти аутентификацию. + Autentisering krävs för att försätta ett program i vänteläge även då ett program hindrar det. + Засвідчення потрібно, щоб призупнити систему, коли програми намагаються першкодити цьому. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.suspend + + + + Hibernate the system + Den Ruhezustand des Systems aktivieren + Αδρανοποίηση του συτήματος + Mettre le système en hibernation + A rendszer hibernálása + Ibernare il sistema + Hibernacja systemu + Hibernar o sistema + Перевести систему в спящий режим + Försätt systemet i viloläge + Приспати систему + Authentication is required for hibernating the system. + Legitimierung ist zum Aktivieren des Ruhezustands des Systems notwendig. + Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος. + Authentification requise pour mettre le système en hibernation. + Hitelesítés szükséges a rendszer hibernálásához. + Autenticazione richiesta per ibernare il sistema. + Wymagane jest uwierzytelnienie, aby zahibernować system. + É necessária autenticação para hibernar o sistema. + Чтобы перевести систему в спящий режим, необходимо пройти аутентификацию. + Autentisering krävs för att försätta systemet i viloläge. + Засвідчення потрібно, щоб приспати систему. + + auth_admin_keep + auth_admin_keep + yes + + + + + Hibernate the system while other users are logged in + Den Ruhezustand des Systems aktivieren, während andere Benutzer angemeldet sind + Αδρανοποίηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι + Mettre le système en hibernation alors que d'autres utilisateurs sont connectés + A rendszer hibernálása mialatt be vannak jelentkezve más felhasználók + Ibernare il sistema mentre altri utenti sono connessi + Hibernacja systemu, kiedy są zalogowani inni użytkownicy + Hibernar o sistema enquanto outros usuários estiverem conectados + Перевести систему в спящий режим, несмотря на то, что в ней работают другие пользователи + Försätt systemet i viloläge medan andra användare är inloggade + Приспати систему, коли інші користувачі в ній + Authentication is required for hibernating the system while other users are logged in. + Legitimierung ist zum Aktivieren des Ruhezustands des Systems notwendig, während andere Benutzer angemeldet sind. + Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι. + Authentification requise pour mettre le système en hibernation alors que d'autres utilisateurs sont connectés. + Hitelesítés szükséges a rendszer hibernálásához miközben be vannak jelentkezve más felhasználók. + Autenticazione richiesta per ibernare il sistema mentre altri utenti sono connessi. + Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy są zalogowani inni użytkownicy. + É necessária autenticação para hibernar o sistema enquanto outros usuários estiverem conectados. + Чтобы перевести систему в спящий режим, несмотря на то, что в ней работают другие пользователи, необходимо пройти аутентификацию. + Autentisering krävs för att försätta systemet i viloläge medan andra användare är inloggade. + Засвідчення потрібно, щоб присипання систему, коли інші користувачі в ній. + + auth_admin_keep + auth_admin_keep + yes + + org.freedesktop.login1.hibernate + + + + Hibernate the system while an application asked to inhibit it + Das System in den Ruhezustand versetzen, während eine Anwendung wünscht dies zu verhindern + Αδρανοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί + Mettre le système en hibernation alors qu'une application a demandé de l'empêcher + A rendszer hibernálása miközben egy alkalmazás ennek meggátlását kérte + Ibernare il sistema mentre un'applicazione chiede di inibirne l'azione + Hibernacja systemu, kiedy program zażądał jej wstrzymania + Hibernar o sistema enquanto um aplicativo solicitou inibição + Перевести систему в спящий режим, несмотря на то, что приложение запросило блокировку + Försätt systemet i viloläge även då ett program hindrar det + Приспати систему, коли програми намагаються першкодити цьому + Authentication is required for hibernating the system while an application asked to inhibit it. + Legitimierung ist zum Versetzen des System in den Ruhezustand notwendig, während eine Anwendung wünscht dies zu verhindern. + Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί. + Authentification requise pour mettre le système en hibernation alors qu'une application a demandé de l'empêcher. + Hitelesítés szükséges a rendszer hibernálásához miközben egy alkalmazás ennek meggátlását kérte. + Autenticazione richiesta per ibernare il sistema mentre un'applicazione chiede di inibirne l'azione. + Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy program zażądał jej wstrzymania. + É necessária autenticação para hibernar o sistema enquanto um aplicativo solicitou inibição. + Чтобы перевести систему в спящий режим, несмотря на то, что приложение запросило блокировку, необходимо пройти аутентификацию. + Autentisering krävs för att försätta ett program i viloläge även då ett program hindrar det. + Засвідчення потрібно, щоб приспати систему, коли програми намагаються першкодити цьому. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.login1.hibernate + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.machine1.policy b/SOURCES/org.freedesktop.machine1.policy new file mode 100644 index 0000000..d7998b8 --- /dev/null +++ b/SOURCES/org.freedesktop.machine1.policy @@ -0,0 +1,34 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Log into a local container + In einem lokalen Container anmelden + Connexion dans un conteneur local + Bejelentkezés helyi konténerbe + Accedi in un container locale + Logowanie do lokalnego kontenera + Conectar a um contêiner local + Зайти в локальный контейнер + Logga till en lokal behållare + Authentication is required to log into a local container + Legitimierung ist zum Anmelden in einem lokalen Container notwendig + Authentification requise pour permettre la connexion dans un conteneur local. + Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe. + Autenticazione richiesta per accedere in un container locale + Wymagane jest uwierzytelnienie, aby zalogować się do lokalnego kontenera + É necessária autenticação para se conectar a um contêiner local. + Autentisering krävs för att tillåta loggning till en lokal behållare. + + auth_admin + auth_admin + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.systemd1.policy b/SOURCES/org.freedesktop.systemd1.policy new file mode 100644 index 0000000..f7e013c --- /dev/null +++ b/SOURCES/org.freedesktop.systemd1.policy @@ -0,0 +1,118 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Send passphrase back to system + Passphrase zurück an das System senden + Αποστολή του συνθηματικού πίσω στο σύστημα + Renvoyer la phrase secrète au système + Jelmondat visszaküldése a rendszernek + Inviare la frase segreta (passphrase) al sistema + Wysłanie hasła z powrotem do systemu + Enviar frase secreta de volta ao sistema + Отправить пароль системе + Skicka tillbaka lösenfras till system + Надіслати пароль назад у систему + Authentication is required to send the entered passphrase back to the system. + Legitimierung ist zum Senden des eingegebenen Kennworts zurück an das System notwendig. + Απαιτείται πιστοποίηση για αποστολή του εισερχόμενου συνθηματικού πίσω στο σύστημα. + Authentification requise pour renvoyer la phrase secrète au système. + Hitelesítés szükséges a bevitt jelmondat visszaküldéséhez a rendszernek. + Autenticazione richiesta per inviare la frase segreta (passphrase) al sistema. + Wymagane jest uwierzytelnienie, aby wysłać podane hasło z powrotem do systemu. + É necessária autenticação para enviar a frase secreta informada de volta ao sistema. + Чтобы отправить пароль системе, необходимо пройти аутентификацию. + Autentisering krävs för att skicka tillbaka den angivna lösenfrasen till systemet. + Засвідчення потрібно, щоб надіслати введений пароль назад у систему. + + no + no + auth_admin_keep + + /usr/lib/systemd/systemd-reply-password + + + + Manage system services or units + Systemdienste und Einheiten verwalten + Gérer les services système ou les unités + Rendszerszolgáltatások vagy -egységek kezelése + Gestisci i servizi o le unità di sistema + Zarządzanie usługami lub jednostkami systemu + Gerenciar unidades e serviços do sistema + Управление системными службами и юнитами + Hantera systemtjänster eller enheter + Authentication is required to manage system services or units. + Legitimierung ist notwendig für die Verwaltung von Systemdiensten und Einheiten + Authentification requise pour gérer les services système ou les unités. + Hitelesítés szükséges a rendszerszolgáltatások vagy -egységek kezeléséhez. + Autenticazione richiesta per gestire servizi e unità di sistema. + Wymagane jest uwierzytelnienie, aby zarządzać usługami lub jednostkami systemu. + É necessária autenticação para gerenciar unidades e serviços do sistema. + Для управления системными службами и юнитами, необходимо пройти аутентификацию. + Autentisering krävs för att hantera systemtjänster eller enheter. + + auth_admin + auth_admin + auth_admin_keep + + + + + Manage system service or unit files + Systemdienste und Einheitendateien verwalten + Gérer le service système ou ses fichiers unités + Rendszerszolgáltatás- vagy egységfájlok kezelése + Gestisci i file dei servizi o delle unità di sistema + Zarządzanie plikami usług lub jednostek systemu + Gerenciar arquivos de unidades e serviços do sistema + Управление файлами конфигурации системных служб и юнитов + Hantera systemtjänster eller enhetsfiler + Authentication is required to manage system service or unit files. + Legitimierung ist notwendig für die Verwaltung von Systemdiensten und Einheitendateien. + Authentification requise pour gérer le service système ou ses fichiers unités. + Hitelesítés szükséges a rendszerszolgáltatás- vagy egységfájlok kezeléséhez. + Autenticazione richiesta per gestire i file dei servizi o delle unità di sistema. + Wymagane jest uwierzytelnienie, aby zarządzać plikami usług lub jednostek systemu. + É necessária autenticação para gerenciar arquivos "unit" e "service" do sistema. + Для управления файлами конфигурации системных служб и юнитов, необходимо пройти аутентификацию. + Autentisering krävs för att hantera systemtjänster eller enhetsfiler. + + auth_admin + auth_admin + auth_admin_keep + + + + + Reload the systemd state + Den systemd-Zustand neu laden + Recharger l'état de systemd + A systemd állapotának újratöltése + Riavviare lo stato di systemd + Ponowne wczytanie stanu systemd + Recarregar o estado do sistema + Перечитать конфигурацию systemd + Läs om tillståndet för systemd + Authentication is required to reload the systemd state. + Legitimierung ist zum erneuten Laden des systemd-Zustands notwendig. + Authentification requise pour recharger l'état de systemd + Hitelesítés szükséges a systemd állapotának újratöltéséhez. + Autenticazione richiesta per riavviare lo stato di sistemd. + Wymagane jest uwierzytelnienie, aby ponownie wczytać stan systemd. + É necessária autenticação para recarregar o estado do sistema. + Чтобы заставить systemd перечитать конфигурацию, необходимо пройти аутентификацию. + Autentisering krävs för att läsa om tillståndet för systemd. + + auth_admin + auth_admin + auth_admin_keep + + + + \ No newline at end of file diff --git a/SOURCES/org.freedesktop.timedate1.policy b/SOURCES/org.freedesktop.timedate1.policy new file mode 100644 index 0000000..e9f4c96 --- /dev/null +++ b/SOURCES/org.freedesktop.timedate1.policy @@ -0,0 +1,130 @@ + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Set system time + Die Systemzeit festlegen + Ορισμός ώρας συστήματος + Définir l'heure du système + Rendszeridő beállítása + Configura l'orario di sistema + Ustawienie czasu systemu + Definir horário do sistema + Настроить системное время + Ange systemtid + Вказати системний час + Authentication is required to set the system time. + Legitimierung ist zum Festlegen der Systemzeit notwendig. + Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος. + Authentification requise pour définir l'heure du système. + Hitelesítés szükséges a rendszeridő beállításához. + Autenticazione richiesta per configurare l'orario di sistema. + Wymagane jest uwierzytelnienie, aby ustawić czas systemu. + É necessária autenticação para definir o horário do sistema. + Чтобы настроить системное время, необходимо пройти аутентификацию. + Autentisering krävs för ange systemtiden. + Засвідчення потрібно, щоб вказати системний час. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + org.freedesktop.timedate1.set-timezone org.freedesktop.timedate1.set-ntp + + + + Set system timezone + Die Systemzeitzone festlegen + Ορισμός ζώνης ώρας συστήματος + Définir le fuseau horaire du système + Rendszer időzónájának beállítása + Configura il fuso orario di sistema + Ustawienie strefy czasowej systemu + Definir fuso horário do sistema + Настроить часовой пояс + Ange systemets tidszon + Вказати системний часовий пояс + Authentication is required to set the system timezone. + Legitimierung ist zum Festlegen der Systemzeitzone notwendig. + Απαιτείται πιστοποίηση για να ορίσετε την ώρα ζώνης του συστήματος. + Authentification requise pour définir le fuseau horaire du système. + Hitelesítés szükséges a rendszer időzónájának beállításához. + Autenticazione richiesta per configurare il fuso orario di sistema. + Wymagane jest uwierzytelnienie, aby ustawić strefę czasową systemu. + É necessária autenticação para definir o fuso horário do sistema. + Чтобы настроить часовой пояс, необходимо пройти аутентификацию. + Autentisering krävs för att ange systemets tidszon. + Засвідчення потрібно, щоб вказати системний часовий пояс. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Set RTC to local timezone or UTC + Echtzeituhr auf lokale Zeitzone oder UTC setzen + Ορισμός RTC στην τοπική ζώνη ώρας ή UTC + Positionner l'horloge matérielle à l'heure locale ou sur le temps universel coordonné (UTC) + Az RTC beállítása helyi időzónára vagy UTC-re + Configura l'orologio di sistema (RTC) al fuso orario locale o al tempo civile (UTC) + Ustawienie RTC na lokalną strefę czasową lub strefę UTC + Definir o relógio do sistema (RTC) para fuso horário local ou UTC + Установить аппаратные часы по местному времени или по Гринвичу + Sätt realtidsklocka (RTC) till lokal tidszon eller koordinerad universell tid (UTC) + Вкажіть RTC для локального часового поясу або UTC + Authentication is required to control whether the RTC stores the local or UTC time. + Legitimierung ist notwendig zum Festlegen, ob die Echtzeituhr auf lokale Zeitzone oder UTC eingestellt ist. + Απαιτείται πιστοποίηση για να ελέγξετε αν το RTC αποθηκεύει την τοπική ή την ώρα UTC. + Authentification requise pour positionner l'horloge matérielle à l'heure locale ou sur le temps universel coordonné (UTC). + Hitelesítés szükséges az RTC beállításához a helyi időzóna vagy UTC tárolására. + Autenticazione richiesta per verificare se l'orologio di sistema (RTC) è configurato all'orario locale o al tempo civile (UTC). + Wymagane jest uwierzytelnienie, aby kontrolować, czy RTC przechowuje czas lokalny lub czas UTC. + É necessária autenticação para controlar se o RTC deve, ou não, armazenar o horário local ou de UTC. + Чтобы контролировать, установлены аппаратные часы по местному времени или по Гринвичу, необходимо пройти аутентификацию. + Autentisering krävs för att kunna kontrollera huruvida realtidsklockan (RTC) lagrar den lokala eller koordinerade universella tiden (UTC). + Засвідчення потрібно, щоб контролювати, чи RTC зберігає час, чи UTC. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + Turn network time synchronization on or off + Netzwerkzeitabgeich ein- oder ausschalten + Ενεργοποίηση/Απενεργοποίηση συγχρονισμού ώρας δικτύου + Activer ou désactiver la synchronisation de l'heure avec le réseau + Hálózati időszinkronizáció be- vagy kikapcsolása + Abilita o meno la sincronizzazione dell'orario in rete + Włączenie lub wyłączenie synchronizacji czasu przez sieć + Ligar/desligar a sincronização do horário em rede + Включить или выключить синхронизацию времени по сети + Växla synkronisering av nätverkstid på och av + Увімкнути або вимкнути синхронізування через мережу + Authentication is required to control whether network time synchronization shall be enabled. + Legitimierung ist zum Festlegen, ob Netzwerkzeitabgeich eingeschaltet sein soll, erforderlich. + Απαιτείται πιστοποίηση για να ελέγξετε αν ο συγχρονισμός ώρας δικτύου θα ενεργοποιηθεί. + Authentification requise pour activer ou désactiver la synchronisation de l'heure avec le réseau. + Hitelesítés szükséges a hálózati időszinkronizáció engedélyezéséhez. + Autenticazione richiesta per verificare se la sincronizzazione dell'orario in rete possa essere attivata. + Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację czasu przez sieć. + É necessária autenticação para controlar se deve ser habilitada, ou não, a sincronização de horário através de rede. + Чтобы включить или выключить синхронизацию времени по сети, необходимо пройти аутентификацию. + Autentisering krävs för att kontrollera huruvida synkronisering av nätverkstid ska vara aktiverat. + Засвідчення потрібно, щоб контролювати, чи синхронізування часу через мережу запущено. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + \ No newline at end of file diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index debe9b3..95d164a 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -7,7 +7,7 @@ Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd Version: 219 -Release: 19%{?dist}.13 +Release: 30%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: A System and Service Manager @@ -26,6 +26,13 @@ Source4: rc.local Source5: 60-alias-kmsg.rules # Stop-gap, just to ensure things work fine with rsyslog without having to change the package right-away Source6: listen.conf +Source7: org.freedesktop.hostname1.policy +Source8: org.freedesktop.import1.policy +Source9: org.freedesktop.locale1.policy +Source10: org.freedesktop.login1.policy +Source11: org.freedesktop.machine1.policy +Source12: org.freedesktop.systemd1.policy +Source13: org.freedesktop.timedate1.policy # RHEL-specific Patch0001: 0001-kernel-install-add-fedora-specific-callouts-to-new-k.patch @@ -290,28 +297,151 @@ Patch0259: 0259-device-rework-how-we-enter-tentative-state.patch Patch0260: 0260-core-Do-not-bind-a-mount-unit-to-a-device-if-it-was-.patch Patch0261: 0261-logind-set-RemoveIPC-no-by-default.patch Patch0262: 0262-sysv-generator-follow-symlinks-in-etc-rc.d-init.d.patch -Patch0263: 0263-man-RemoveIPC-is-set-to-no-on-rhel.patch -Patch0264: 0264-makefile-disable-udev-tests.patch -Patch0265: 0265-sysv-generator-test-always-log-to-console.patch +Patch0263: 0263-sysv-generator-test-always-log-to-console.patch +Patch0264: 0264-man-RemoveIPC-is-set-to-no-on-rhel.patch +Patch0265: 0265-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch Patch0266: 0266-test-sysv-generator-Check-for-network-online.target.patch -Patch0267: 0267-Avoid-tmp-being-mounted-as-tmpfs-without-the-user-s-.patch -Patch0268: 0268-udev-fibre-channel-fix-NPIV-support.patch -Patch0269: 0269-ata_id-unreverse-WWN-identifier.patch -Patch0270: 0270-Fixup-WWN-bytes-for-big-endian-systems.patch -Patch0271: 0271-Revert-udev-fibre-channel-fix-NPIV-support.patch -Patch0272: 0272-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch -Patch0273: 0273-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch -Patch0274: 0274-Revert-journald-turn-ForwardToSyslog-off-by-default.patch -Patch0275: 0275-journal-fix-error-handling-when-compressing-journal-.patch -Patch0276: 0276-journal-irrelevant-coding-style-fixes.patch -Patch0277: 0277-fstab-generator-cescape-device-name-in-root-fsck-ser.patch -Patch0278: 0278-manager-reduce-complexity-of-unit_gc_sweep-3507.patch -Patch0279: 0279-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch -Patch0280: 0280-logind-process-session-inhibitor-fds-at-higher-prior.patch -Patch0281: 0281-sd-event-expose-the-event-loop-iteration-counter-via.patch -Patch0282: 0282-manager-Only-invoke-a-single-sigchld-per-unit-within.patch -Patch0283: 0283-manager-Fixing-a-debug-printf-formatting-mistake.patch -Patch0284: 0284-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch +Patch0267: 0267-makefile-disable-udev-tests.patch +Patch0268: 0268-arm-aarch64-detect-virt-check-dmi.patch +Patch0269: 0269-detect-virt-dmi-look-for-KVM.patch +Patch0270: 0270-Revert-journald-turn-ForwardToSyslog-off-by-default.patch +Patch0271: 0271-terminal-util-when-resetting-terminals-don-t-wait-fo.patch +Patch0272: 0272-basic-terminal-util-introduce-SYSTEMD_COLORS-environ.patch +Patch0273: 0273-ask-password-don-t-abort-when-message-is-missing.patch +Patch0274: 0274-sysv-generator-do-not-join-dependencies-on-one-line-.patch +Patch0275: 0275-udev-fibre-channel-fix-NPIV-support.patch +Patch0276: 0276-ata_id-unreverse-WWN-identifier.patch +Patch0277: 0277-Fixup-WWN-bytes-for-big-endian-systems.patch +Patch0278: 0278-sd-journal-introduce-has_runtime_files-and-has_persi.patch +Patch0279: 0279-journalctl-improve-error-messages-when-the-specified.patch +Patch0280: 0280-journalctl-show-friendly-info-when-using-b-on-runtim.patch +Patch0281: 0281-journalctl-make-journalctl-dev-sda-work.patch +Patch0282: 0282-journalctl-add-match-for-the-current-boot-when-calle.patch +Patch0283: 0283-man-clarify-what-happens-when-journalctl-is-called-w.patch +Patch0284: 0284-core-downgrade-warning-about-duplicate-device-names.patch +Patch0285: 0285-udev-downgrade-a-few-warnings-to-debug-messages.patch +Patch0286: 0286-man-LEVEL-in-systemd-analyze-set-log-level-is-not-op.patch +Patch0287: 0287-Revert-udev-fibre-channel-fix-NPIV-support.patch +Patch0288: 0288-udev-path-id-fibre-channel-NPIV-use-fc_vport-s-port_.patch +Patch0289: 0289-systemctl-is-active-failed-should-return-0-if-at-lea.patch +Patch0290: 0290-rules-set-SYSTEMD_READY-0-on-DM_UDEV_DISABLE_OTHER_R.patch +Patch0291: 0291-s390-add-personality-support.patch +Patch0292: 0292-socket_address_listen-do-not-rely-on-errno.patch +Patch0293: 0293-path_id-reintroduce-by-path-links-for-virtio-block-d.patch +Patch0294: 0294-journal-fix-error-handling-when-compressing-journal-.patch +Patch0295: 0295-journal-irrelevant-coding-style-fixes.patch +Patch0296: 0296-install-follow-unit-file-symlinks-in-usr-but-not-etc.patch +Patch0297: 0297-core-look-for-instance-when-processing-template-name.patch +Patch0298: 0298-core-improve-error-message-when-starting-template-wi.patch +Patch0299: 0299-man-tmpfiles.d-add-note-about-permissions-and-owners.patch +Patch0300: 0300-tmpfiles-don-t-follow-symlinks-when-adjusting-ACLs-f.patch +Patch0301: 0301-udev-filter-out-non-sensically-high-onboard-indexes-.patch +Patch0302: 0302-test-execute-add-tests-for-RuntimeDirectory.patch +Patch0303: 0303-core-fix-group-ownership-when-Group-is-set.patch +Patch0304: 0304-fstab-generator-cescape-device-name-in-root-fsck-ser.patch +Patch0305: 0305-core-add-new-RandomSec-setting-for-time-units.patch +Patch0306: 0306-core-rename-Random-to-RandomizedDelay.patch +Patch0307: 0307-journal-remote-change-owner-of-var-log-journal-remot.patch +Patch0308: 0308-Add-Seal-option-in-the-configuration-file-for-journa.patch +Patch0309: 0309-tests-fix-make-check-failure.patch +Patch0310: 0310-device-make-sure-to-not-ignore-re-plugged-device.patch +Patch0311: 0311-device-Ensure-we-have-sysfs-path-before-comparing.patch +Patch0312: 0312-core-fix-memory-leak-on-set-default-enable-disable-e.patch +Patch0313: 0313-nspawn-fix-minor-memory-leak.patch +Patch0314: 0314-basic-fix-error-memleak-in-socket-util.patch +Patch0315: 0315-core-fix-memory-leak-in-manager_run_generators.patch +Patch0316: 0316-modules-load-fix-memory-leak.patch +Patch0317: 0317-core-fix-memory-leak-on-failed-preset-all.patch +Patch0318: 0318-sd-bus-fix-memory-leak-in-test-bus-chat.patch +Patch0319: 0319-core-fix-memory-leak-in-transient-units.patch +Patch0320: 0320-bus-fix-leak-in-error-path.patch +Patch0321: 0321-shared-logs-show-fix-memleak-in-add_matches_for_unit.patch +Patch0322: 0322-logind-introduce-LockedHint-and-SetLockedHint-3238.patch +Patch0323: 0323-import-use-the-old-curl-api.patch +Patch0324: 0324-importd-drop-dkr-support.patch +Patch0325: 0325-import-add-support-for-gpg2-for-verifying-imported-i.patch +Patch0326: 0326-nspawn-when-connected-to-pipes-for-stdin-stdout-pass.patch +Patch0327: 0327-mount-remove-obsolete-n.patch +Patch0328: 0328-core-don-t-log-job-status-message-in-case-job-was-ef.patch +Patch0329: 0329-core-use-an-AF_UNIX-SOCK_DGRAM-socket-for-cgroup-age.patch +Patch0330: 0330-logind-process-session-inhibitor-fds-at-higher-prior.patch +Patch0331: 0331-Teach-bus_append_unit_property_assignment-about-Dele.patch +Patch0332: 0332-sd-netlink-fix-deep-recursion-in-message-destruction.patch +Patch0333: 0333-add-REMOTE_ADDR-and-REMOTE_PORT-for-Accept-yes.patch +Patch0334: 0334-core-don-t-dispatch-load-queue-when-setting-Slice-fo.patch +Patch0335: 0335-run-make-slice-work-in-conjunction-with-scope.patch +Patch0336: 0336-myhostname-fix-timeout-if-ipv6-is-disabled.patch +Patch0337: 0337-readahead-do-not-increase-nr_requests-for-root-fs-bl.patch +Patch0338: 0338-manager-reduce-complexity-of-unit_gc_sweep-3507.patch +Patch0339: 0339-hwdb-selinuxify-a-bit-3460.patch +Patch0340: 0340-udevadm-explicitly-relabel-etc-udev-hwdb.bin-after-r.patch +Patch0341: 0341-systemctl-return-diffrent-error-code-if-service-exis.patch +Patch0342: 0342-systemctl-Replace-init-script-error-codes-with-enum-.patch +Patch0343: 0343-systemctl-rework-systemctl-status-a-bit.patch +Patch0344: 0344-journal-verify-don-t-hit-SIGFPE-when-determining-pro.patch +Patch0345: 0345-journal-avoid-mapping-empty-data-and-field-hash-tabl.patch +Patch0346: 0346-journal-when-verifying-journal-files-handle-empty-on.patch +Patch0347: 0347-journal-explain-the-error-when-we-find-a-non-DATA-ob.patch +Patch0348: 0348-journalctl-properly-detect-empty-journal-files.patch +Patch0349: 0349-journal-uppercase-first-character-in-verify-error-me.patch +Patch0350: 0350-journalctl-make-sure-journalctl-f-t-unmatched-blocks.patch +Patch0351: 0351-journalctl-don-t-print-No-entries-in-quiet-mode.patch +Patch0352: 0352-sd-event-expose-the-event-loop-iteration-counter-via.patch +Patch0353: 0353-manager-Only-invoke-a-single-sigchld-per-unit-within.patch +Patch0354: 0354-manager-Fixing-a-debug-printf-formatting-mistake.patch +Patch0355: 0355-core-support-IEC-suffixes-for-RLIMIT-stuff.patch +Patch0356: 0356-core-accept-time-units-for-time-based-resource-limit.patch +Patch0357: 0357-time-util-add-parse_time-which-is-like-parse_sec-but.patch +Patch0358: 0358-core-support-soft-hard-ranges-for-RLIMIT-options.patch +Patch0359: 0359-core-fix-rlimit-parsing.patch +Patch0360: 0360-core-dump-rlim_cur-too.patch +Patch0361: 0361-install-fix-disable-via-unit-file-path.patch +Patch0362: 0362-manager-don-t-skip-sigchld-handler-for-main-and-cont.patch +Patch0363: 0363-units-increase-watchdog-timeout-to-3min-for-all-our-.patch +Patch0364: 0364-core-bump-net.unix.max_dgram_qlen-really-early-durin.patch +Patch0365: 0365-core-fix-priority-ordering-in-notify-handling.patch +Patch0366: 0366-tests-fix-personality-tests-on-ppc64-and-aarch64.patch +Patch0367: 0367-systemctl-consider-service-running-only-when-it-is-i.patch +Patch0368: 0368-install-do-not-crash-when-processing-empty-masked-un.patch +Patch0369: 0369-Revert-install-fix-disable-via-unit-file-path.patch +Patch0370: 0370-systemctl-allow-disable-on-the-unit-file-path-but-wa.patch +Patch0371: 0371-tmpfiles-enforce-ordering-when-executing-lines.patch +Patch0372: 0372-Introduce-bus_unit_check_load_state-helper.patch +Patch0373: 0373-core-use-bus_unit_check_load_state-in-transaction_ad.patch +Patch0374: 0374-udev-path_id-correct-segmentation-fault-due-to-missi.patch +Patch0375: 0375-rules-load-sg-driver-also-when-scsi_target-appears-4.patch +Patch0376: 0376-fix-gcc-warnings-about-uninitialized-variables.patch +Patch0377: 0377-journalctl-rework-code-that-checks-whether-we-have-a.patch +Patch0378: 0378-journalctl-Improve-boot-ID-lookup.patch +Patch0379: 0379-journalctl-only-have-a-single-exit-path-from-main.patch +Patch0380: 0380-journalctl-free-all-command-line-argument-objects.patch +Patch0381: 0381-journalctl-rename-boot_id_t-to-BootId.patch +Patch0382: 0382-util-introduce-CMSG_FOREACH-macro-and-make-use-of-it.patch +Patch0383: 0383-journald-don-t-employ-inner-loop-for-reading-from-in.patch +Patch0384: 0384-journald-fix-count-of-object-meta-fields.patch +Patch0385: 0385-journal-cat-return-a-correct-error-not-1.patch +Patch0386: 0386-journalctl-introduce-short-options-for-since-and-unt.patch +Patch0387: 0387-journal-s-Envalid-Invalid.patch +Patch0388: 0388-journald-dispatch-SIGTERM-SIGINT-with-a-low-priority.patch +Patch0389: 0389-lz4-fix-size-check-which-had-no-chance-of-working-on.patch +Patch0390: 0390-journal-normalize-priority-of-logging-sources.patch +Patch0391: 0391-Fix-miscalculated-buffer-size-and-uses-of-size-unlim.patch +Patch0392: 0392-journal-Drop-monotonicity-check-when-appending-to-jo.patch +Patch0393: 0393-journalctl-unify-how-we-free-boot-id-lists-a-bit.patch +Patch0394: 0394-journalctl-don-t-trust-the-per-field-entry-tables-wh.patch +Patch0395: 0395-units-remove-udev-control-socket-when-systemd-stops-.patch +Patch0396: 0396-logind-don-t-assert-if-the-slice-is-missing.patch +Patch0397: 0397-core-enable-transient-unit-support-for-slice-units.patch +Patch0398: 0398-sd-bus-bump-message-queue-size.patch +Patch0399: 0399-install-fix-disable-when-etc-systemd-system-is-a-sym.patch +Patch0400: 0400-rules-add-NVMe-rules-3136.patch +Patch0401: 0401-rules-introduce-disk-by-id-model_serial-symlinks-for.patch +Patch0402: 0402-rules-fix-for-possible-whitespace-in-the-model-attri.patch +Patch0403: 0403-systemctl-pid1-do-not-warn-about-missing-install-inf.patch +Patch0404: 0404-systemctl-core-ignore-masked-units-in-preset-all.patch +Patch0405: 0405-shared-install-handle-dangling-aliases-as-an-explici.patch +Patch0406: 0406-shared-install-ignore-unit-symlinks-when-doing-prese.patch +Patch0407: 0407-40-redhat.rules-don-t-hoplug-memory-on-s390x.patch %global num_patches %{lua: c=0; for i,p in ipairs(patches) do c=c+1; end; print(c);} @@ -329,6 +459,8 @@ BuildRequires: glib2-devel BuildRequires: gobject-introspection-devel BuildRequires: libblkid-devel BuildRequires: xz-devel +BuildRequires: zlib-devel +BuildRequires: bzip2-devel BuildRequires: libidn-devel BuildRequires: libcurl-devel BuildRequires: kmod-devel @@ -354,7 +486,6 @@ BuildRequires: autoconf BuildRequires: libtool BuildRequires: git BuildRequires: libmount-devel -BuildRequires: tree Requires(post): coreutils Requires(post): gawk @@ -415,6 +546,7 @@ License: LGPLv2+ and MIT Requires: %{name} = %{version}-%{release} Provides: libudev-devel = %{version} Obsoletes: libudev-devel < 183 +Requires: %{name}-libs = %{version}-%{release} %description devel Development headers and auxiliary files for developing applications for systemd. @@ -431,6 +563,7 @@ SysV compatibility tools for systemd Summary: Python 2 bindings for systemd License: LGPLv2+ Requires: %{name} = %{version}-%{release} +Requires: %{name}-libs = %{version}-%{release} %description python This package contains bindings which allow Python 2 programs to use @@ -441,6 +574,7 @@ Summary: Libraries for adding libudev support to applications that use gl Conflicts: filesystem < 3 License: LGPLv2+ Requires: %{name}-libs = %{version}-%{release} +Requires: glib2 >= 2.42 %description -n libgudev1 This package contains the libraries that make it easier to use libudev @@ -555,7 +689,6 @@ CONFIGURE_OPTS=( --disable-timesyncd --disable-kdbus --disable-terminal ---disable-importd --enable-gtk-doc --enable-compat-libs --disable-sysusers @@ -566,6 +699,7 @@ CONFIGURE_OPTS=( ) +RPM_OPT_FLAGS="$RPM_OPT_FLAGS -O0" %configure "${CONFIGURE_OPTS[@]}" make %{?_smp_mflags} GCC_COLORS="" V=1 @@ -575,6 +709,15 @@ make %{?_smp_mflags} GCC_COLORS="" V=1 find %{buildroot} \( -name '*.a' -o -name '*.la' \) -delete sed -i 's/L+/#/' %{buildroot}/usr/lib/tmpfiles.d/etc.conf +rm -f %{buildroot}%{_datadir}/polkit-1/actions/org.freedesktop.*.policy +install -m 0644 %{SOURCE7} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE8} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE9} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE10} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE11} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE12} %{buildroot}%{_datadir}/polkit-1/actions/ +install -m 0644 %{SOURCE13} %{buildroot}%{_datadir}/polkit-1/actions/ + # udev links mkdir -p %{buildroot}/%{_sbindir} ln -sf ../bin/udevadm %{buildroot}%{_sbindir}/udevadm @@ -718,8 +861,8 @@ getent group floppy >/dev/null 2>&1 || groupadd -r -g 19 floppy >/dev/null 2>&1 getent group systemd-journal >/dev/null 2>&1 || groupadd -r -g 190 systemd-journal 2>&1 || : getent group systemd-bus-proxy >/dev/null 2>&1 || groupadd -r systemd-bus-proxy 2>&1 || : getent passwd systemd-bus-proxy >/dev/null 2>&1 || useradd -r -l -g systemd-bus-proxy -d / -s /sbin/nologin -c "systemd Bus Proxy" systemd-bus-proxy >/dev/null 2>&1 || : -getent group systemd-network >/dev/null 2>&1 || groupadd -r systemd-network 2>&1 || : -getent passwd systemd-network >/dev/null 2>&1 || useradd -r -l -g systemd-network -d / -s /sbin/nologin -c "systemd Network Management" systemd-network >/dev/null 2>&1 || : +getent group systemd-network >/dev/null 2>&1 || groupadd -r -g 192 systemd-network 2>&1 || : +getent passwd systemd-network >/dev/null 2>&1 || useradd -r -u 192 -l -g systemd-network -d / -s /sbin/nologin -c "systemd Network Management" systemd-network >/dev/null 2>&1 || : systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd.service >/dev/null 2>&1 || : @@ -929,8 +1072,9 @@ getent group systemd-journal-gateway >/dev/null 2>&1 || groupadd -r -g 191 syste getent passwd systemd-journal-gateway >/dev/null 2>&1 || useradd -r -l -u 191 -g systemd-journal-gateway -d %{_localstatedir}/log/journal -s /sbin/nologin -c "Journal Gateway" systemd-journal-gateway >/dev/null 2>&1 || : getent group systemd-journal-remote >/dev/null 2>&1 || groupadd -r systemd-journal-remote 2>&1 || : getent passwd systemd-journal-remote >/dev/null 2>&1 || useradd -r -l -g systemd-journal-remote -d /%{_localstatedir}/log/journal/remote -s /sbin/nologin -c "Journal Remote" systemd-journal-remote >/dev/null 2>&1 || : +getent group systemd-journal >/dev/null 2>&1 || groupadd -r -g 190 systemd-journal 2>&1 || : getent group systemd-journal-upload >/dev/null 2>&1 || groupadd -r systemd-journal-upload 2>&1 || : -getent passwd systemd-journal-upload >/dev/null 2>&1 || useradd -r -l -g systemd-journal-upload -d /%{_localstatedir}/log/journal/upload -s /sbin/nologin -c "Journal Upload" systemd-journal-upload >/dev/null 2>&1 || : +getent passwd systemd-journal-upload >/dev/null 2>&1 || useradd -r -l -g systemd-journal-upload -G systemd-journal -d /%{_localstatedir}/log/journal/upload -s /sbin/nologin -c "Journal Upload" systemd-journal-upload >/dev/null 2>&1 || : %post journal-gateway %systemd_post systemd-journal-gatewayd.socket systemd-journal-gatewayd.service @@ -957,8 +1101,8 @@ getent passwd systemd-journal-upload >/dev/null 2>&1 || useradd -r -l -g systemd %systemd_postun_with_restart systemd-networkd.service systemd-networkd-wait-online.service %pre resolved -getent group systemd-resolve >/dev/null 2>&1 || groupadd -r systemd-resolve 2>&1 || : -getent passwd systemd-resolve >/dev/null 2>&1 || useradd -r -l -g systemd-resolve -d / -s /sbin/nologin -c "systemd Resolver" systemd-resolve >/dev/null 2>&1 || : +getent group systemd-resolve >/dev/null 2>&1 || groupadd -r -g 193 systemd-resolve 2>&1 || : +getent passwd systemd-resolve >/dev/null 2>&1 || useradd -r -u 193 -l -g systemd-resolve -d / -s /sbin/nologin -c "systemd Resolver" systemd-resolve >/dev/null 2>&1 || : %post resolved %systemd_post systemd-resolved.service @@ -1020,6 +1164,7 @@ getent passwd systemd-resolve >/dev/null 2>&1 || useradd -r -l -g systemd-resolv %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.locale1.conf %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.timedate1.conf %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.machine1.conf +%config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freedesktop.import1.conf %config(noreplace) %{_sysconfdir}/systemd/system.conf %config(noreplace) %{_sysconfdir}/systemd/user.conf %config(noreplace) %{_sysconfdir}/systemd/logind.conf @@ -1094,6 +1239,7 @@ getent passwd systemd-resolve >/dev/null 2>&1 || useradd -r -l -g systemd-resolv %exclude %{_prefix}/lib/systemd/systemd-resolve-host %exclude %{_prefix}/lib/systemd/systemd-journal-upload %{_prefix}/lib/systemd/systemd-* +%{_prefix}/lib/systemd/import-pubring.gpg %{_prefix}/lib/udev %exclude %{_sysconfdir}/udev/rules.d/80-net-setup-link.rules %{_prefix}/lib/tmpfiles.d/systemd.conf @@ -1143,6 +1289,7 @@ getent passwd systemd-resolve >/dev/null 2>&1 || useradd -r -l -g systemd-resolv %{_datadir}/dbus-1/system-services/org.freedesktop.locale1.service %{_datadir}/dbus-1/system-services/org.freedesktop.timedate1.service %{_datadir}/dbus-1/system-services/org.freedesktop.machine1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.import1.service %dir %{_datadir}/polkit-1 %dir %{_datadir}/polkit-1/actions %{_datadir}/polkit-1/actions/org.freedesktop.systemd1.policy @@ -1151,6 +1298,7 @@ getent passwd systemd-resolve >/dev/null 2>&1 || useradd -r -l -g systemd-resolv %{_datadir}/polkit-1/actions/org.freedesktop.locale1.policy %{_datadir}/polkit-1/actions/org.freedesktop.timedate1.policy %{_datadir}/polkit-1/actions/org.freedesktop.machine1.policy +%{_datadir}/polkit-1/actions/org.freedesktop.import1.policy %{_libdir}/pkgconfig/systemd.pc %{_datadir}/pkgconfig/udev.pc %{_datadir}/bash-completion/completions/* @@ -1272,56 +1420,174 @@ getent passwd systemd-resolve >/dev/null 2>&1 || useradd -r -l -g systemd-resolv %{_mandir}/man8/systemd-resolved.* %changelog -* Wed Jul 27 2016 Lukas Nykryn - 219-19.13 -- core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent notification (#1305608) -- logind: process session/inhibitor fds at higher priority (#1305608) +* Tue Sep 13 2016 Lukas Nykryn - 219-30 +- systemctl,pid1: do not warn about missing install info with "preset" (#1373950) +- systemctl/core: ignore masked units in preset-all (#1375097) +- shared/install: handle dangling aliases as an explicit case, report nicely (#1375097) +- shared/install: ignore unit symlinks when doing preset-all (#1375097) +- 40-redhat.rules: don't hoplug memory on s390x (#1370161) + +* Mon Sep 05 2016 Lukas Nykryn - 219-29 +- fix gcc warnings about uninitialized variables (#1318994) +- journalctl: rework code that checks whether we have access to /var/log/journal (#1318994) +- journalctl: Improve boot ID lookup (#1318994) +- journalctl: only have a single exit path from main() (#1318994) +- journalctl: free all command line argument objects (#1318994) +- journalctl: rename boot_id_t to BootId (#1318994) +- util: introduce CMSG_FOREACH() macro and make use of it everywhere (#1318994) +- journald: don't employ inner loop for reading from incoming sockets (#1318994) +- journald: fix count of object meta fields (#1318994) +- journal-cat: return a correct error, not -1 (#1318994) +- journalctl: introduce short options for --since and --until (#1318994) +- journal: s/Envalid/Invalid/ (#1318994) +- journald: dispatch SIGTERM/SIGINT with a low priority (#1318994) +- lz4: fix size check which had no chance of working on big-endian (#1318994) +- journal: normalize priority of logging sources (#1318994) +- Fix miscalculated buffer size and uses of size-unlimited sprintf() function. (#1318994) +- journal: Drop monotonicity check when appending to journal file (#1318994) +- journalctl: unify how we free boot id lists a bit (#1318994) +- journalctl: don't trust the per-field entry tables when looking for boot IDs (#1318994) +- units: remove udev control socket when systemd stops the socket unit (#49) (#1370133) +- logind: don't assert if the slice is missing (#1371437) +- core: enable transient unit support for slice units (#1370299) +- sd-bus: bump message queue size (#1371205) +- install: fix disable when /etc/systemd/system is a symlink (#1285996) +- rules: add NVMe rules (#3136) (#1274651) +- rules: introduce disk/by-id (model_serial) symlinks for NVMe drives (#3974) (#1274651) +- rules: fix for possible whitespace in the "model" attribute (#1274651) + +* Fri Aug 19 2016 Lukas Nykryn - 219-27 +- tmpfiles: enforce ordering when executing lines (#1365870) +- Introduce bus_unit_check_load_state() helper (#1256858) +- core: use bus_unit_check_load_state() in transaction_add_job_and_dependencies() (#1256858) +- udev/path_id: correct segmentation fault due to missing NULL check (#1365556) +- rules: load sg driver also when scsi_target appears (#45) (#1322773) + +* Tue Aug 09 2016 Lukas Nykryn - 219-26 +- install: do not crash when processing empty (masked) unit file (#1159308) +- Revert "install: fix disable via unit file path" (#1348208) +- systemctl: allow disable on the unit file path, but warn about it (#3806) (#1348208) + +* Thu Aug 04 2016 Lukas Nykryn - 219-25 +- units: increase watchdog timeout to 3min for all our services (#1267707) +- core: bump net.unix.max_dgram_qlen really early during boot (#1267707) +- core: fix priority ordering in notify-handling (#1267707) +- tests: fix personality tests on ppc64 and aarch64 (#1361049) +- systemctl: consider service running only when it is in active or reloading state (#3874) (#1362461) + +* Mon Jul 18 2016 Lukas Nykryn - 219-24 +- manager: don't skip sigchld handler for main and control pid for services (#3738) (#1342173) + +* Tue Jul 12 2016 Lukas Nykryn - 219-23 +- udevadm: explicitly relabel /etc/udev/hwdb.bin after rename (#1350756) +- systemctl: return diffrent error code if service exist or not (#3385) (#1047466) +- systemctl: Replace init script error codes with enum (#3400) (#1047466) +- systemctl: rework "systemctl status" a bit (#1047466) +- journal-verify: don't hit SIGFPE when determining progress (#1350232) +- journal: avoid mapping empty data and field hash tables (#1350232) +- journal: when verifying journal files, handle empty ones nicely (#1350232) +- journal: explain the error when we find a non-DATA object that is compressed (#1350232) +- journalctl: properly detect empty journal files (#1350232) +- journal: uppercase first character in verify error messages (#1350232) +- journalctl: make sure 'journalctl -f -t unmatched' blocks (#1350232) +- journalctl: don't print -- No entries -- in quiet mode (#1350232) - sd-event: expose the event loop iteration counter via sd_event_get_iteration() (#1342173) - manager: Only invoke a single sigchld per unit within a cleanup cycle (#1342173) - manager: Fixing a debug printf formatting mistake (#1342173) -- manager: don't skip sigchld handler for main and control pid for services (#3738) (#1342173) - -* Tue Jun 14 2016 Lukas Nykryn - 219-19.12 +- core: support IEC suffixes for RLIMIT stuff (#1351415) +- core: accept time units for time-based resource limits (#1351415) +- time-util: add parse_time(), which is like parse_sec() but allows specification of default time unit if none is specified (#1351415) +- core: support ranges for RLIMIT options (#1351415) +- core: fix rlimit parsing (#1351415) +- core: dump rlim_cur too (#1351415) +- install: fix disable via unit file path (#1348208) + +* Wed Jun 22 2016 Lukas Nykryn - 219-22 +- nspawn: when connected to pipes for stdin/stdout, pass them as-is to PID 1 (#1307080) +- mount: remove obsolete -n (#1339721) +- core: don't log job status message in case job was effectively NOP (#3199) (#1280014) +- core: use an AF_UNIX/SOCK_DGRAM socket for cgroup agent notification (#1305608) +- logind: process session/inhibitor fds at higher priority (#1305608) +- Teach bus_append_unit_property_assignment() about 'Delegate' property (#1337922) +- sd-netlink: fix deep recursion in message destruction (#1330593) +- add REMOTE_ADDR and REMOTE_PORT for Accept=yes (#1341154) +- core: don't dispatch load queue when setting Slice= for transient units (#1343904) +- run: make --slice= work in conjunction with --scope (#1343904) +- myhostname: fix timeout if ipv6 is disabled (#1330973) +- readahead: do not increase nr_requests for root fs block device (#1314559) - manager: reduce complexity of unit_gc_sweep (#3507) (#1344556) +- hwdb: selinuxify a bit (#3460) (#1343648) -* Thu May 26 2016 Lukas Nykryn - 219-19.11 -- fstab-generator: cescape device name in root-fsck service (#1306126) - -* Tue May 24 2016 Lukáš Nykrýn - 219-19.10 -- get rid of ldconfig.service (#1338892) - -* Thu Apr 28 2016 Lukas Nykryn - 219-19.9 +* Mon May 23 2016 Lukas Nykryn - 219-21 +- path_id: reintroduce by-path links for virtio block devices (#952567) - journal: fix error handling when compressing journal objects (#1292447) - journal: irrelevant coding style fixes (#1292447) - -* Wed Apr 20 2016 Lukas Nykryn - 219-19.8 +- install: follow unit file symlinks in /usr, but not /etc when looking for [Install] data (#1159308) +- core: look for instance when processing template name (#1159308) +- core: improve error message when starting template without instance (#1142369) +- man/tmpfiles.d: add note about permissions and ownership of symlinks (#1296288) +- tmpfiles: don't follow symlinks when adjusting ACLs, fille attributes, access modes or ownership (#1296288) +- udev: filter out non-sensically high onboard indexes reported by the kernel (#1230210) +- test-execute: add tests for RuntimeDirectory (#1324826) +- core: fix group ownership when Group is set (#1324826) +- fstab-generator: cescape device name in root-fsck service (#1306126) +- core: add new RandomSec= setting for time units (#1305279) +- core: rename Random* to RandomizedDelay* (#1305279) +- journal-remote: change owner of /var/log/journal/remote and create /var/lib/systemd/journal-upload (#1327303) +- Add Seal option in the configuration file for journald-remote (#1329233) +- tests: fix make check failure (#1159308) +- device: make sure to not ignore re-plugged device (#1332606) +- device: Ensure we have sysfs path before comparing. (#1332606) +- core: fix memory leak on set-default, enable, disable etc (#1331667) +- nspawn: fix minor memory leak (#1331667) +- basic: fix error/memleak in socket-util (#1331667) +- core: fix memory leak in manager_run_generators() (#1331667) +- modules-load: fix memory leak (#1331667) +- core: fix memory leak on failed preset-all (#1331667) +- sd-bus: fix memory leak in test-bus-chat (#1331667) +- core: fix memory leak in transient units (#1331667) +- bus: fix leak in error path (#1331667) +- shared/logs-show: fix memleak in add_matches_for_unit (#1331667) +- logind: introduce LockedHint and SetLockedHint (#3238) (#1335499) +- import: use the old curl api (#1284974) +- importd: drop dkr support (#1284974) +- import: add support for gpg2 for verifying imported images (#1284974) + +* Thu Mar 10 2016 Lukas Nykryn - 219-20 +- run: synchronously wait until the scope unit we create is started (#1272368) +- device: rework how we enter tentative state (#1283579) +- core: Do not bind a mount unit to a device, if it was from mountinfo (#1283579) +- logind: set RemoveIPC=no by default (#1284588) +- sysv-generator: follow symlinks in /etc/rc.d/init.d (#1285492) +- sysv-generator test: always log to console (#1279034) +- man: RemoveIPC is set to no on rhel (#1284588) +- Avoid /tmp being mounted as tmpfs without the user's will (#1298109) +- test sysv-generator: Check for network-online.target. (#1279034) +- arm/aarch64: detect-virt: check dmi (#1278165) +- detect-virt: dmi: look for KVM (#1278165) - Revert "journald: turn ForwardToSyslog= off by default" (#1285642) - -* Fri Mar 04 2016 Lukas Nykryn - 219-19.7 +- terminal-util: when resetting terminals, don't wait for carrier (#1266745) +- basic/terminal-util: introduce SYSTEMD_COLORS environment variable (#1247963) +- ask-password: don't abort when message is missing (#1261136) +- sysv-generator: do not join dependencies on one line, split them (#1288600) +- udev: fibre channel: fix NPIV support (#1266934) +- ata_id: unreverse WWN identifier (#1273306) +- Fixup WWN bytes for big-endian systems (#1273306) +- sd-journal: introduce has_runtime_files and has_persistent_files (#1082179) +- journalctl: improve error messages when the specified boot is not found (#1082179) +- journalctl: show friendly info when using -b on runtime journal only (#1082179) +- journalctl: make "journalctl /dev/sda" work (#947636) +- journalctl: add match for the current boot when called with devpath (#947636) +- man: clarify what happens when journalctl is called with devpath (#947636) +- core: downgrade warning about duplicate device names (#1296249) +- udev: downgrade a few warnings to debug messages (#1289461) +- man: LEVEL in systemd-analyze set-log level is not optional (#1268336) - Revert "udev: fibre channel: fix NPIV support" (#1266934) - udev: path-id: fibre channel NPIV - use fc_vport's port_name (#1266934) +- systemctl: is-active/failed should return 0 if at least one unit is in given state (#1254650) - rules: set SYSTEMD_READY=0 on DM_UDEV_DISABLE_OTHER_RULES_FLAG=1 only with ADD event (#1312011) - -* Thu Feb 25 2016 Lukas Nykryn - 219-19.6 -- ata_id: unreverse WWN identifier (#1308795) -- Fixup WWN bytes for big-endian systems (#1308795) - -* Wed Feb 03 2016 Lukas Nykryn - 219-19.5 -- udev: fibre channel: fix NPIV support (#1266934) - -* Wed Jan 13 2016 Lukas Nykryn - 219-19.4 -- Avoid /tmp being mounted as tmpfs without the user's will (#1298109) - -* Thu Dec 10 2015 Lukas Nykryn - 219-19.3 -- sysv-generator: follow symlinks in /etc/rc.d/init.d (#1288005) -- man: RemoveIPC is set to no on rhel (#1284588) - -* Fri Nov 27 2015 Lukas Nykryn - 219-19.2 -- device: rework how we enter tentative state (#1283579) -- core: Do not bind a mount unit to a device, if it was from mountinfo (#1283579) -- logind: set RemoveIPC=no by default (#1284588) - -* Wed Nov 18 2015 Lukas Nykryn - 219-19.1 -- run: synchronously wait until the scope unit we create is started (#1283192) +- s390: add personality support (#1300344) +- socket_address_listen - do not rely on errno (#1316452) * Mon Oct 12 2015 Lukas Nykryn - 219-19 - udev: make naming for virtio devices opt-in (#1269216)