diff --git a/SOURCES/0499-Revert-udev-net_id-add-support-for-phys_port_name-at.patch b/SOURCES/0499-Revert-udev-net_id-add-support-for-phys_port_name-at.patch deleted file mode 100644 index 92b8938..0000000 --- a/SOURCES/0499-Revert-udev-net_id-add-support-for-phys_port_name-at.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 6cbd97527f6d33a140072131785547e898ee4c7a Mon Sep 17 00:00:00 2001 -From: Lukas Nykryn -Date: Tue, 15 Aug 2017 12:30:03 +0200 -Subject: [PATCH] Revert "udev: net_id: add support for phys_port_name - attribute (#4506)" - -This reverts commit 192545bc67fed763ac54761ca067b9c2f93ecdd1. - -This caused change of the names for sfc driver. - -Resolves: #1477285 ---- - src/udev/udev-builtin-net_id.c | 24 ++++++------------------ - 1 file changed, 6 insertions(+), 18 deletions(-) - -diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c -index 7c154355d..19e1f2631 100644 ---- a/src/udev/udev-builtin-net_id.c -+++ b/src/udev/udev-builtin-net_id.c -@@ -38,7 +38,7 @@ - * o[d] -- on-board device index number - * s[f][d] -- hotplug slot index number - * x -- MAC address -- * [P]ps[f][n|d/] -+ * [P]ps[f][d/] - * -- PCI geographical location - * [P]ps[f][u][..][c][i] - * -- USB port number chain -@@ -134,7 +134,7 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { - unsigned dev_port = 0; - size_t l; - char *s; -- const char *attr, *port_name; -+ const char *attr; - int idx; - - /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ -@@ -161,15 +161,10 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { - if (attr) - dev_port = strtol(attr, NULL, 10); - -- /* kernel provided front panel port name for multiple port PCI device */ -- port_name = udev_device_get_sysattr_value(dev, "phys_port_name"); -- - s = names->pci_onboard; - l = sizeof(names->pci_onboard); - l = strpcpyf(&s, l, "o%d", idx); -- if (port_name) -- l = strpcpyf(&s, l, "n%s", port_name); -- else if (dev_port > 0) -+ if (dev_port > 0) - l = strpcpyf(&s, l, "d%d", dev_port); - if (l == 0) - names->pci_onboard[0] = '\0'; -@@ -204,7 +199,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { - unsigned domain, bus, slot, func, dev_id = 0; - size_t l; - char *s; -- const char *attr, *port_name; -+ const char *attr; - struct udev_device *pci = NULL; - char slots[256], str[256]; - _cleanup_closedir_ DIR *dir = NULL; -@@ -225,9 +220,6 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { - } - } - -- /* kernel provided front panel port name for multiple port PCI device */ -- port_name = udev_device_get_sysattr_value(dev, "phys_port_name"); -- - /* compose a name based on the raw kernel's PCI bus, slot numbers */ - s = names->pci_path; - l = sizeof(names->pci_path); -@@ -236,9 +228,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { - l = strpcpyf(&s, l, "p%us%u", bus, slot); - if (func > 0 || is_pci_multifunction(names->pcidev)) - l = strpcpyf(&s, l, "f%d", func); -- if (port_name) -- l = strpcpyf(&s, l, "n%s", port_name); -- else if (dev_id > 0) -+ if (dev_id > 0) - l = strpcpyf(&s, l, "d%d", dev_id); - if (l == 0) - names->pci_path[0] = '\0'; -@@ -288,9 +278,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { - l = strpcpyf(&s, l, "s%d", hotplug_slot); - if (func > 0 || is_pci_multifunction(names->pcidev)) - l = strpcpyf(&s, l, "f%d", func); -- if (port_name) -- l = strpcpyf(&s, l, "n%s", port_name); -- else if (dev_id > 0) -+ if (dev_id > 0) - l = strpcpyf(&s, l, "d%d", dev_id); - if (l == 0) - names->pci_slot[0] = '\0'; diff --git a/SOURCES/0499-tests-use-XFS-as-root-filesystem-for-system-tests.patch b/SOURCES/0499-tests-use-XFS-as-root-filesystem-for-system-tests.patch new file mode 100644 index 0000000..7dff683 --- /dev/null +++ b/SOURCES/0499-tests-use-XFS-as-root-filesystem-for-system-tests.patch @@ -0,0 +1,50 @@ +From e82e71d82496b7dd3268db62a89f215b4b38508f Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 24 Jul 2017 18:47:36 +0200 +Subject: [PATCH] tests: use XFS as root filesystem for system tests + +On RHEL-7 we don't have mount.ext3 in initramfs. + +RHEL-only + +Resolves: #1475870 +--- + test/TEST-02-CRYPTSETUP/test.sh | 4 ++-- + test/test-functions | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh +index 4be2365e2..6e5c53d8b 100755 +--- a/test/TEST-02-CRYPTSETUP/test.sh ++++ b/test/TEST-02-CRYPTSETUP/test.sh +@@ -38,7 +38,7 @@ test_setup() { + echo -n test >$TESTDIR/keyfile + cryptsetup -q luksFormat ${LOOPDEV}p2 $TESTDIR/keyfile + cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile +- mkfs.ext3 -L var /dev/mapper/varcrypt ++ mkfs.xfs -L var /dev/mapper/varcrypt + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + mkdir -p $TESTDIR/root/var +@@ -74,7 +74,7 @@ EOF + cat $initdir/etc/crypttab | ddebug + + cat >>$initdir/etc/fstab < -Date: Fri, 25 Aug 2017 13:13:50 +0200 -Subject: [PATCH] sysctl: fix uninitialized variable - -RHEL-only - -Reported-by: HATAYAMA Daisuke - -Resolves: #1485121 ---- - src/sysctl/sysctl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c -index bb2bea7cd..7fb016cee 100644 ---- a/src/sysctl/sysctl.c -+++ b/src/sysctl/sysctl.c -@@ -91,7 +91,7 @@ static int apply_sysctl(const char *property, const char *value) { - } - - static int apply_all(OrderedHashmap *sysctl_options) { -- int r; -+ int r = 0; - char *property, *value; - Iterator i; - diff --git a/SOURCES/0500-tests-use-fdisk-instead-of-sfdisk.patch b/SOURCES/0500-tests-use-fdisk-instead-of-sfdisk.patch new file mode 100644 index 0000000..d15f912 --- /dev/null +++ b/SOURCES/0500-tests-use-fdisk-instead-of-sfdisk.patch @@ -0,0 +1,60 @@ +From 5655999840f9c3d8b55a40c1751df400b425178a Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 24 Jul 2017 13:25:19 +0200 +Subject: [PATCH] tests: use fdisk instead of sfdisk + +In RHEL7 we have an older version of sfdisk that exits with an error +when executed with sfdisk script that is used in upstream to create +partitions on root disk. + +Let's use equivalent fdisk commands to achieve the (more less) same +result. + +Also default size of disk image is bumped to 400M. Previous 300M doesn't +work, probably due to some fdisk bug. Size of second partiotion (/var in +TEST-02-CRYPTSETUP) is bumped to 50M to accommodate space requirements +of xfs filesystem. + +RHEL-only + +Resolves: #1475870 +--- + test/test-functions | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/test/test-functions b/test/test-functions +index f8950e31e..cf5612370 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -141,15 +141,26 @@ install_missing_libraries() { + create_empty_image() { + rm -f "$TESTDIR/rootdisk.img" + # Create the blank file to use as a root filesystem +- dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=300 ++ dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=400 + LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img) + [ -b "$LOOPDEV" ] || return 1 + echo "LOOPDEV=$LOOPDEV" >> $STATEFILE +- sfdisk "$LOOPDEV" < +Date: Tue, 15 Aug 2017 12:30:03 +0200 +Subject: [PATCH] Revert "udev: net_id: add support for phys_port_name + attribute (#4506)" + +This reverts commit 192545bc67fed763ac54761ca067b9c2f93ecdd1. + +This caused change of the names for sfc driver. + +Resolves: #1477285 +--- + src/udev/udev-builtin-net_id.c | 24 ++++++------------------ + 1 file changed, 6 insertions(+), 18 deletions(-) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 7c154355d..19e1f2631 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -38,7 +38,7 @@ + * o[d] -- on-board device index number + * s[f][d] -- hotplug slot index number + * x -- MAC address +- * [P]ps[f][n|d/] ++ * [P]ps[f][d/] + * -- PCI geographical location + * [P]ps[f][u][..][c][i] + * -- USB port number chain +@@ -134,7 +134,7 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { + unsigned dev_port = 0; + size_t l; + char *s; +- const char *attr, *port_name; ++ const char *attr; + int idx; + + /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ +@@ -161,15 +161,10 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { + if (attr) + dev_port = strtol(attr, NULL, 10); + +- /* kernel provided front panel port name for multiple port PCI device */ +- port_name = udev_device_get_sysattr_value(dev, "phys_port_name"); +- + s = names->pci_onboard; + l = sizeof(names->pci_onboard); + l = strpcpyf(&s, l, "o%d", idx); +- if (port_name) +- l = strpcpyf(&s, l, "n%s", port_name); +- else if (dev_port > 0) ++ if (dev_port > 0) + l = strpcpyf(&s, l, "d%d", dev_port); + if (l == 0) + names->pci_onboard[0] = '\0'; +@@ -204,7 +199,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + unsigned domain, bus, slot, func, dev_id = 0; + size_t l; + char *s; +- const char *attr, *port_name; ++ const char *attr; + struct udev_device *pci = NULL; + char slots[256], str[256]; + _cleanup_closedir_ DIR *dir = NULL; +@@ -225,9 +220,6 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + } + } + +- /* kernel provided front panel port name for multiple port PCI device */ +- port_name = udev_device_get_sysattr_value(dev, "phys_port_name"); +- + /* compose a name based on the raw kernel's PCI bus, slot numbers */ + s = names->pci_path; + l = sizeof(names->pci_path); +@@ -236,9 +228,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + l = strpcpyf(&s, l, "p%us%u", bus, slot); + if (func > 0 || is_pci_multifunction(names->pcidev)) + l = strpcpyf(&s, l, "f%d", func); +- if (port_name) +- l = strpcpyf(&s, l, "n%s", port_name); +- else if (dev_id > 0) ++ if (dev_id > 0) + l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) + names->pci_path[0] = '\0'; +@@ -288,9 +278,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { + l = strpcpyf(&s, l, "s%d", hotplug_slot); + if (func > 0 || is_pci_multifunction(names->pcidev)) + l = strpcpyf(&s, l, "f%d", func); +- if (port_name) +- l = strpcpyf(&s, l, "n%s", port_name); +- else if (dev_id > 0) ++ if (dev_id > 0) + l = strpcpyf(&s, l, "d%d", dev_id); + if (l == 0) + names->pci_slot[0] = '\0'; diff --git a/SOURCES/0501-udev-ignore-SIGCHLD-from-unexpected-processes-130653.patch b/SOURCES/0501-udev-ignore-SIGCHLD-from-unexpected-processes-130653.patch deleted file mode 100644 index b497247..0000000 --- a/SOURCES/0501-udev-ignore-SIGCHLD-from-unexpected-processes-130653.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 8b998d862e401c252c4323974698691e67846412 Mon Sep 17 00:00:00 2001 -From: Jan Synacek -Date: Tue, 15 Aug 2017 13:29:51 +0200 -Subject: [PATCH] udev: ignore SIGCHLD from unexpected processes (#1306539) - -RHEL-only - -Author: grzegorz.halat@motorolasolutions.com -Resolves: #1306539 ---- - src/udev/udev-event.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c -index bc115f112..0ba079201 100644 ---- a/src/udev/udev-event.c -+++ b/src/udev/udev-event.c -@@ -610,7 +610,11 @@ static int spawn_wait(struct udev_event *event, - event->sigterm = true; - break; - case SIGCHLD: -- if (waitpid(pid, &status, WNOHANG) < 0) -+ if (pid != (pid_t) fdsi.ssi_pid) { -+ log_debug("expected SIGCHLD from '%s' ["PID_FMT"] received from unknown process ["PID_FMT"]. Ignoring", cmd, pid, fdsi.ssi_pid); -+ continue; -+ } -+ if (waitpid(pid, &status, WNOHANG) <= 0) - break; - if (WIFEXITED(status)) { - log_debug("'%s' ["PID_FMT"] exit with return code %i", cmd, pid, WEXITSTATUS(status)); diff --git a/SOURCES/0502-core-unset-sysfs-path-after-transition-to-dead-state.patch b/SOURCES/0502-core-unset-sysfs-path-after-transition-to-dead-state.patch new file mode 100644 index 0000000..9991b10 --- /dev/null +++ b/SOURCES/0502-core-unset-sysfs-path-after-transition-to-dead-state.patch @@ -0,0 +1,49 @@ +From d5ab3fdc9bf9353478e7c0987b3830f14bbdefae Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 22 Jun 2017 14:26:39 +0200 +Subject: [PATCH] core: unset sysfs path after transition to dead state + +Device is gone and most likely it will get garbage collected. However in +cases when it doesn't get gc'ed (because it is referenced by some +other unit, e.g. mount from fstab) we need to unset sysfs. This is +because when device appears next time, possibly, with different sysfs +path we need to update the sysfs path. Current code could end up caching +stale sysfs path forever. + +In reality this is not a problem for normal disks (unless you swap them +during system runtime). However this issue causes failures to mount +filesystems on LVM where sysfs path depends on activation +order (i.e. logical volumes from volume group that is activated first +get assigned lower dm-X numbers and corresponding syspaths). + +Fixes #6126 + +(cherry picked from commit 0e139cac0318de09e6f4c1a4fc61388f7e541ebd) + +Resolves: #1408916 +--- + src/core/device.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/core/device.c b/src/core/device.c +index befbae83f..63a04bdd3 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -474,12 +474,16 @@ static void device_update_found_one(Device *d, bool add, DeviceFound found, bool + * now referenced by the kernel, then we assume the + * kernel knows it now, and udev might soon too. */ + device_set_state(d, DEVICE_TENTATIVE); +- else ++ else { + /* If nobody sees the device, or if the device was + * previously seen by udev and now is only referenced + * from the kernel, then we consider the device is + * gone, the kernel just hasn't noticed it yet. */ ++ + device_set_state(d, DEVICE_DEAD); ++ device_unset_sysfs(d); ++ } ++ + } + + static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) { diff --git a/SOURCES/0502-manager-when-reexecuting-try-to-connect-to-bus-only-.patch b/SOURCES/0502-manager-when-reexecuting-try-to-connect-to-bus-only-.patch deleted file mode 100644 index d66b01e..0000000 --- a/SOURCES/0502-manager-when-reexecuting-try-to-connect-to-bus-only-.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 156f59bc8c84fd0015b8170f6c4af9eadd1b5cfa Mon Sep 17 00:00:00 2001 -From: Michal Sekletar -Date: Fri, 8 Sep 2017 15:41:44 +0200 -Subject: [PATCH] manager: when reexecuting try to connect to bus only when - dbus.service is around (#6773) - -Trying to connect otherwise is pointless, because if socket isn't around -we won't connect. However, when dbus.socket is present we attempt to -connect. That attempt can't succeed because we are then supposed -to activate dbus.service as a response to connection from -us. This results in deadlock. - -Fixes #6303 - -(cherry picked from commit 5463fa0a88f95d2002858592578f9bf4e0d2660a) - -Resolves: #1465737 ---- - src/core/manager.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/src/core/manager.c b/src/core/manager.c -index 287cf6a74..041fac46b 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -799,16 +799,19 @@ static int manager_setup_kdbus(Manager *m) { - - static int manager_connect_bus(Manager *m, bool reexecuting) { - bool try_bus_connect; -+ Unit *u = NULL; - - assert(m); - - if (m->test_run) - return 0; - -+ u = manager_get_unit(m, SPECIAL_DBUS_SERVICE); -+ - try_bus_connect = -- m->kdbus_fd >= 0 || -- reexecuting || -- (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS")); -+ (u && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) && -+ (reexecuting || -+ (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"))); - - /* Try to connect to the busses, if possible. */ - return bus_init(m, try_bus_connect); diff --git a/SOURCES/0503-sysctl-fix-uninitialized-variable.patch b/SOURCES/0503-sysctl-fix-uninitialized-variable.patch new file mode 100644 index 0000000..821541c --- /dev/null +++ b/SOURCES/0503-sysctl-fix-uninitialized-variable.patch @@ -0,0 +1,27 @@ +From 75d982344e59e1dd916c214c5ccb6339c5c94254 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 25 Aug 2017 13:13:50 +0200 +Subject: [PATCH] sysctl: fix uninitialized variable + +RHEL-only + +Reported-by: HATAYAMA Daisuke + +Resolves: #1485121 +--- + src/sysctl/sysctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c +index bb2bea7cd..7fb016cee 100644 +--- a/src/sysctl/sysctl.c ++++ b/src/sysctl/sysctl.c +@@ -91,7 +91,7 @@ static int apply_sysctl(const char *property, const char *value) { + } + + static int apply_all(OrderedHashmap *sysctl_options) { +- int r; ++ int r = 0; + char *property, *value; + Iterator i; + diff --git a/SOURCES/0503-unmount-Pass-in-mount-options-when-remounting-read-o.patch b/SOURCES/0503-unmount-Pass-in-mount-options-when-remounting-read-o.patch deleted file mode 100644 index fe9a804..0000000 --- a/SOURCES/0503-unmount-Pass-in-mount-options-when-remounting-read-o.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 02a5d91ec022be1188875e0f169277cef3b11ad6 Mon Sep 17 00:00:00 2001 -From: Jan Janssen -Date: Mon, 26 Oct 2015 15:13:28 +0100 -Subject: [PATCH] unmount: Pass in mount options when remounting read-only - -man 2 mount says that the mountflags and data parameteres should -match the original values except for the desired changes. We only -bother with the mount options since the only flags we can change -are MS_RDONLY, MS_SYNCHRONOUS and MS_MANDLOCK; which shouldn't -matter too much. - -Fixes: #351 - -(cherry picked from commit 471b48ed2ff6539e7071ff4694c03483c5835639) - -Related: #1312002 ---- - src/core/umount.c | 26 ++++++++++++++++++++------ - 1 file changed, 20 insertions(+), 6 deletions(-) - -diff --git a/src/core/umount.c b/src/core/umount.c -index dd7df194d..bfd8aa5f8 100644 ---- a/src/core/umount.c -+++ b/src/core/umount.c -@@ -28,6 +28,7 @@ - #include - #include - -+#include "fstab-util.h" - #include "list.h" - #include "mount-setup.h" - #include "umount.h" -@@ -39,6 +40,7 @@ - - typedef struct MountPoint { - char *path; -+ char *options; - dev_t devnum; - LIST_FIELDS(struct MountPoint, mount_point); - } MountPoint; -@@ -71,7 +73,7 @@ static int mount_points_list_get(MountPoint **head) { - return -errno; - - for (i = 1;; i++) { -- _cleanup_free_ char *path = NULL; -+ _cleanup_free_ char *path = NULL, *options = NULL; - char *p = NULL; - MountPoint *m; - int k; -@@ -82,15 +84,15 @@ static int mount_points_list_get(MountPoint **head) { - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ -- "%*s" /* (6) mount options */ -+ "%*s" /* (6) mount flags */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%*s " /* (9) file system type */ - "%*s" /* (10) mount source */ -- "%*s" /* (11) mount options 2 */ -+ "%ms" /* (11) mount options */ - "%*[^\n]", /* some rubbish at the end */ -- &path); -- if (k != 1) { -+ &path, &options); -+ if (k != 2) { - if (k == EOF) - break; - -@@ -125,6 +127,9 @@ static int mount_points_list_get(MountPoint **head) { - } - - m->path = p; -+ m->options = options; -+ options = NULL; -+ - LIST_PREPEND(mount_point, *head, m); - } - -@@ -368,6 +373,14 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e - benefits, but might confuse the host, as we remount - the superblock here, not the bind mound. */ - if (detect_container(NULL) <= 0) { -+ _cleanup_free_ char *options = NULL; -+ /* MS_REMOUNT requires that the data parameter -+ * should be the same from the original mount -+ * except for the desired changes. Since we want -+ * to remount read-only, we should filter out -+ * rw (and ro too, because it confuses the kernel) */ -+ (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options); -+ - /* We always try to remount directories - * read-only first, before we go on and umount - * them. -@@ -384,7 +397,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e - * alias read-only we hence should be - * relatively safe regarding keeping the fs we - * can otherwise not see dirty. */ -- mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL); -+ log_info("Remounting '%s' read-only with options '%s'.", m->path, options); -+ (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options); - } - - /* Skip / and /usr since we cannot unmount that diff --git a/SOURCES/0504-shutdown-don-t-remount-ro-network-filesystems.-6588.patch b/SOURCES/0504-shutdown-don-t-remount-ro-network-filesystems.-6588.patch deleted file mode 100644 index 0581aa2..0000000 --- a/SOURCES/0504-shutdown-don-t-remount-ro-network-filesystems.-6588.patch +++ /dev/null @@ -1,76 +0,0 @@ -From c6bb93f0b564d6c0eea9e35197b66521693b2078 Mon Sep 17 00:00:00 2001 -From: NeilBrown -Date: Thu, 31 Aug 2017 02:48:25 +1000 -Subject: [PATCH] shutdown: don't remount,ro network filesystems. (#6588) - -systemd-shutdown is run after the network is stopped, -so remounting a network filesystem read-only can hang. -A simple umount is the most useful thing that can -be done for a network filesystem once the network is down. - -(cherry picked from commit 9cbc4547702aac28466c497f720038b9e2dc510c) - -Resolves: #1312002 ---- - src/core/umount.c | 17 ++++++++++++----- - 1 file changed, 12 insertions(+), 5 deletions(-) - -diff --git a/src/core/umount.c b/src/core/umount.c -index bfd8aa5f8..6e8ccc794 100644 ---- a/src/core/umount.c -+++ b/src/core/umount.c -@@ -41,6 +41,7 @@ - typedef struct MountPoint { - char *path; - char *options; -+ char *type; - dev_t devnum; - LIST_FIELDS(struct MountPoint, mount_point); - } MountPoint; -@@ -73,7 +74,7 @@ static int mount_points_list_get(MountPoint **head) { - return -errno; - - for (i = 1;; i++) { -- _cleanup_free_ char *path = NULL, *options = NULL; -+ _cleanup_free_ char *path = NULL, *options = NULL, *type = NULL; - char *p = NULL; - MountPoint *m; - int k; -@@ -87,11 +88,11 @@ static int mount_points_list_get(MountPoint **head) { - "%*s" /* (6) mount flags */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ -- "%*s " /* (9) file system type */ -+ "%ms " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%ms" /* (11) mount options */ - "%*[^\n]", /* some rubbish at the end */ -- &path, &options); -+ &path, &type, &options); - if (k != 2) { - if (k == EOF) - break; -@@ -129,6 +130,8 @@ static int mount_points_list_get(MountPoint **head) { - m->path = p; - m->options = options; - options = NULL; -+ m->type = type; -+ type = NULL; - - LIST_PREPEND(mount_point, *head, m); - } -@@ -371,8 +374,12 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e - /* If we are in a container, don't attempt to - read-only mount anything as that brings no real - benefits, but might confuse the host, as we remount -- the superblock here, not the bind mound. */ -- if (detect_container(NULL) <= 0) { -+ the superblock here, not the bind mount. -+ If the filesystem is a network fs, also skip the -+ remount. It brings no value (we cannot leave -+ a "dirty fs") and could hang if the network is down. */ -+ if (detect_container(NULL) <= 0 && -+ !fstype_is_network(m->type)) { - _cleanup_free_ char *options = NULL; - /* MS_REMOUNT requires that the data parameter - * should be the same from the original mount diff --git a/SOURCES/0504-udev-ignore-SIGCHLD-from-unexpected-processes-130653.patch b/SOURCES/0504-udev-ignore-SIGCHLD-from-unexpected-processes-130653.patch new file mode 100644 index 0000000..9c73445 --- /dev/null +++ b/SOURCES/0504-udev-ignore-SIGCHLD-from-unexpected-processes-130653.patch @@ -0,0 +1,30 @@ +From 461c10112d74ab223226554f2bb73aabaef43c9a Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 15 Aug 2017 13:29:51 +0200 +Subject: [PATCH] udev: ignore SIGCHLD from unexpected processes (#1306539) + +RHEL-only + +Author: grzegorz.halat@motorolasolutions.com +Resolves: #1306539 +--- + src/udev/udev-event.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index bc115f112..0ba079201 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -610,7 +610,11 @@ static int spawn_wait(struct udev_event *event, + event->sigterm = true; + break; + case SIGCHLD: +- if (waitpid(pid, &status, WNOHANG) < 0) ++ if (pid != (pid_t) fdsi.ssi_pid) { ++ log_debug("expected SIGCHLD from '%s' ["PID_FMT"] received from unknown process ["PID_FMT"]. Ignoring", cmd, pid, fdsi.ssi_pid); ++ continue; ++ } ++ if (waitpid(pid, &status, WNOHANG) <= 0) + break; + if (WIFEXITED(status)) { + log_debug("'%s' ["PID_FMT"] exit with return code %i", cmd, pid, WEXITSTATUS(status)); diff --git a/SOURCES/0505-compile-with-Werror.patch b/SOURCES/0505-compile-with-Werror.patch new file mode 100644 index 0000000..2ba63a3 --- /dev/null +++ b/SOURCES/0505-compile-with-Werror.patch @@ -0,0 +1,83 @@ +From 382877acc6c029e59e359a076d203ca03b4b9e9e Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 3 May 2017 14:34:36 +0200 +Subject: [PATCH] compile with -Werror + +The maybe-uninitialized flag has to be disabled, because gcc on RHEL7 +reports tons of obvious false-positive warnings when variables are +wrapped with _cleanup_. + +Also, LTO is better to be disabled. According to gcc folks, it makes +debugging really hard and is not really recommended on RHEL7. Plus it +makes the compilation fail with + +In function '__ppoll_alias', + inlined from 'bus_poll' at src/libsystemd/sd-bus/sd-bus.c:2822:11: +/usr/include/bits/poll2.h:71:9: warning: call to '__ppoll_chk_warn' declared with attribute warning: ppoll called with fds buffer too small file nfds entries + return __ppoll_chk (__fds, __nfds, __timeout, __ss, __bos (__fds)); + +That is also a gcc bug, already fixed in the gcc upstream +(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61886). + +Resolves: #1447937 +--- + configure.ac | 12 ++---------- + src/core/main.c | 1 - + src/login/logind-session.c | 2 +- + 3 files changed, 3 insertions(+), 12 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 2734368dc..def9fe5ce 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -187,7 +187,8 @@ CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ + -Wno-unused-parameter \ + -Wno-missing-field-initializers \ + -Wno-unused-result \ +- -Werror=overflow \ ++ -Werror \ ++ -Wno-error=maybe-uninitialized \ + -Wdate-time \ + -Wnested-externs \ + -ffast-math \ +@@ -208,15 +209,6 @@ AS_CASE([$CC], [*clang*], + -Wno-gnu-variable-sized-type-not-at-end \ + ])]) + +-AC_ARG_ENABLE([lto], AS_HELP_STRING([--disable-lto], [Disable Link time optimization])) +-AS_IF([test "x$enable_lto" != "xno"], [ +-AS_CASE([$CFLAGS], [*-O[[12345\ ]]*], [ +- CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [-flto -ffat-lto-objects]) +- CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS],[-Wl,-fuse-ld=gold]) +- ], +-[AC_MSG_RESULT([skipping -flto, optimization not enabled])]) +-]) +- + AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags") + + AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*], +diff --git a/src/core/main.c b/src/core/main.c +index 50c9714f7..37e3ea0ce 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1205,7 +1205,6 @@ static int status_welcome(void) { + + static int write_container_id(void) { + const char *c; +- int r; + + c = getenv("container"); + if (isempty(c)) +diff --git a/src/login/logind-session.c b/src/login/logind-session.c +index 4575a029f..daf875a7d 100644 +--- a/src/login/logind-session.c ++++ b/src/login/logind-session.c +@@ -183,7 +183,7 @@ int session_save(Session *s) { + "STATE=%s\n" + "REMOTE=%i\n" + "STOPPING=%i\n", +- (unsigned long) s->user->uid, ++ s->user->uid, + s->user->name, + session_is_active(s), + session_state_to_string(session_get_state(s)), diff --git a/SOURCES/0505-shutdown-fix-incorrect-fscanf-result-check-6806.patch b/SOURCES/0505-shutdown-fix-incorrect-fscanf-result-check-6806.patch deleted file mode 100644 index eea0ee6..0000000 --- a/SOURCES/0505-shutdown-fix-incorrect-fscanf-result-check-6806.patch +++ /dev/null @@ -1,29 +0,0 @@ -From b0630cdbb8f16850f6a62447328df77130059efc Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Wed, 13 Sep 2017 10:08:37 +0200 -Subject: [PATCH] shutdown: fix incorrect fscanf() result check (#6806) - -A correction for 090e3c9796ef6468d4f396610804d62f6ffd797f. - -Fixes: #6796 - -(cherry-picked from: 3d4ec01269244c2d35a781abf748ea9ba57666e2) - -Related: #1312002 ---- - src/core/umount.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/core/umount.c b/src/core/umount.c -index 6e8ccc794..3eec0d459 100644 ---- a/src/core/umount.c -+++ b/src/core/umount.c -@@ -93,7 +93,7 @@ static int mount_points_list_get(MountPoint **head) { - "%ms" /* (11) mount options */ - "%*[^\n]", /* some rubbish at the end */ - &path, &type, &options); -- if (k != 2) { -+ if (k != 3) { - if (k == EOF) - break; - diff --git a/SOURCES/0506-manager-fix-connecting-to-bus-when-dbus-is-actually-.patch b/SOURCES/0506-manager-fix-connecting-to-bus-when-dbus-is-actually-.patch deleted file mode 100644 index b69a75d..0000000 --- a/SOURCES/0506-manager-fix-connecting-to-bus-when-dbus-is-actually-.patch +++ /dev/null @@ -1,34 +0,0 @@ -From f4cfab4baa2365ca1484b7e43a9da434aa102153 Mon Sep 17 00:00:00 2001 -From: Michal Sekletar -Date: Wed, 1 Nov 2017 02:25:48 -0700 -Subject: [PATCH] manager: fix connecting to bus when dbus is actually around - (#7205) - -manager_connect_bus() is called *before* manager_coldplug(). As a last -thing in service_coldplug() we set service state to -s->deserialized_state, and thus before we do that all services are -inactive and try_connect always evaluates to false. To fix that we must -look at deserialized state instead of current unit state. - -Fixes #7146 - -(cherry picked from commit 41dfa61d35c51a584437481d20541d5c3ccfa93d) - -Related: #1465737 ---- - 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 041fac46b..47b09e1e9 100644 ---- a/src/core/manager.c -+++ b/src/core/manager.c -@@ -809,7 +809,7 @@ static int manager_connect_bus(Manager *m, bool reexecuting) { - u = manager_get_unit(m, SPECIAL_DBUS_SERVICE); - - try_bus_connect = -- (u && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) && -+ (u && SERVICE(u)->deserialized_state == SERVICE_RUNNING) && - (reexecuting || - (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"))); - diff --git a/SOURCES/0506-myhostname-don-t-return-any-ipv6-entries-when-ipv6-i.patch b/SOURCES/0506-myhostname-don-t-return-any-ipv6-entries-when-ipv6-i.patch new file mode 100644 index 0000000..683a3cc --- /dev/null +++ b/SOURCES/0506-myhostname-don-t-return-any-ipv6-entries-when-ipv6-i.patch @@ -0,0 +1,42 @@ +From 624fcda36dd376707e3af088b592fe3764b99acf Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 2 May 2017 14:34:17 +0200 +Subject: [PATCH] myhostname: don't return any ipv6 entries when ipv6 is + disabled + +This commit amends the rhel-only 6e5117b83af5998359916f276a9b32f755c0e6f4. + +Resolves: #1444824 +--- + src/nss-myhostname/nss-myhostname.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c +index e197cc752..144c83171 100644 +--- a/src/nss-myhostname/nss-myhostname.c ++++ b/src/nss-myhostname/nss-myhostname.c +@@ -351,6 +351,8 @@ enum nss_status _nss_myhostname_gethostbyname3_r( + *h_errnop = NO_DATA; + return NSS_STATUS_UNAVAIL; + } ++ if (af == AF_INET6 && !socket_ipv6_is_supported()) ++ return NSS_STATUS_UNAVAIL; + + if (is_localhost(name)) { + canonical = "localhost"; +@@ -381,13 +383,9 @@ enum nss_status _nss_myhostname_gethostbyname3_r( + return NSS_STATUS_NOTFOUND; + } + +- if (af == AF_INET6 && !socket_ipv6_is_supported()) { ++ n_addresses = local_addresses(NULL, 0, af, &addresses); ++ if (n_addresses < 0) + 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/SOURCES/0507-automount-ack-automount-requests-even-when-already-m.patch b/SOURCES/0507-automount-ack-automount-requests-even-when-already-m.patch deleted file mode 100644 index 2ed105b..0000000 --- a/SOURCES/0507-automount-ack-automount-requests-even-when-already-m.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 164bd929f1c85026f21ed493d11d3b4d1b94421d Mon Sep 17 00:00:00 2001 -From: Jan Synacek -Date: Wed, 17 Jan 2018 09:13:24 +0100 -Subject: [PATCH] automount: ack automount requests even when already mounted - -If a process accesses an autofs filesystem while systemd is in the -middle of starting the mount unit on top of it, it is possible for the -autofs_ptype_missing_direct request from the kernel to be received after -the mount unit has been fully started: - - systemd forks and execs mount ... - ... access autofs, blocks - mount exits ... - systemd receives SIGCHLD ... - ... kernel sends request - systemd receives request ... - -systemd needs to respond to this request, otherwise the kernel will -continue to block access to the mount point. - -(cherry picked from commit e7d54bf58789545a9eb0b3964233defa0b007318) - -Resolves: #1535135 ---- - src/core/automount.c | 28 ++++++++++++++++------------ - 1 file changed, 16 insertions(+), 12 deletions(-) - -diff --git a/src/core/automount.c b/src/core/automount.c -index 4e066613d..9e05963e9 100644 ---- a/src/core/automount.c -+++ b/src/core/automount.c -@@ -692,7 +692,7 @@ static int automount_start_expire(Automount *a) { - automount_dispatch_expire, a); - } - --static void automount_enter_runnning(Automount *a) { -+static void automount_enter_running(Automount *a) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - struct stat st; - int r; -@@ -718,18 +718,22 @@ static void automount_enter_runnning(Automount *a) { - goto fail; - } - -- if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) -+ /* The mount unit may have been explicitly started before we got the -+ * autofs request. Ack it to unblock anything waiting on the mount point. */ -+ if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) { - log_unit_info(UNIT(a)->id, - "%s's automount point already active?", UNIT(a)->id); -- else { -- r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), -- JOB_REPLACE, true, &error, NULL); -- if (r < 0) { -- log_unit_warning(UNIT(a)->id, -- "%s failed to queue mount startup job: %s", -- UNIT(a)->id, bus_error_message(&error, r)); -- goto fail; -- } -+ automount_send_ready(a, a->tokens, 0); -+ return; -+ } -+ -+ r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), -+ JOB_REPLACE, true, &error, NULL); -+ if (r < 0) { -+ log_unit_warning(UNIT(a)->id, -+ "%s failed to queue mount startup job: %s", -+ UNIT(a)->id, bus_error_message(&error, r)); -+ goto fail; - } - - r = automount_start_expire(a); -@@ -953,7 +957,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo - goto fail; - } - -- automount_enter_runnning(a); -+ automount_enter_running(a); - break; - - case autofs_ptype_expire_direct: diff --git a/SOURCES/0507-core-execute-fix-fork-fail-handling-in-exec_spawn.patch b/SOURCES/0507-core-execute-fix-fork-fail-handling-in-exec_spawn.patch new file mode 100644 index 0000000..2574d5d --- /dev/null +++ b/SOURCES/0507-core-execute-fix-fork-fail-handling-in-exec_spawn.patch @@ -0,0 +1,30 @@ +From 03118775f6a9bf505a65dd0b86a6d2de2e3493a3 Mon Sep 17 00:00:00 2001 +From: lc85446 +Date: Thu, 26 Nov 2015 11:46:40 +0800 +Subject: [PATCH] core:execute: fix fork() fail handling in exec_spawn() + +If pid < 0 after fork(), 0 is always returned because r = +exec_context_load_environment() has exited successfully. + +This will make the caller of exec_spawn() not able to handle +the fork() error case and make systemd abort assert() possibly. + +Cherry-picked from: 74129a127676e4f0edac0db4296c103e76ec6694 +Resolves: #1437114 +--- + src/core/execute.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/execute.c b/src/core/execute.c +index 4265b9c34..e68276973 100644 +--- a/src/core/execute.c ++++ b/src/core/execute.c +@@ -1977,7 +1977,7 @@ int exec_spawn(ExecCommand *command, + NULL); + pid = fork(); + if (pid < 0) +- return log_unit_error_errno(params->unit_id, r, "Failed to fork: %m"); ++ return log_unit_error_errno(params->unit_id, errno, "Failed to fork: %m"); + + if (pid == 0) { + int exit_status; diff --git a/SOURCES/0508-fix-compilation-after-commit-382877acc6c029e59e359a0.patch b/SOURCES/0508-fix-compilation-after-commit-382877acc6c029e59e359a0.patch new file mode 100644 index 0000000..1f546b2 --- /dev/null +++ b/SOURCES/0508-fix-compilation-after-commit-382877acc6c029e59e359a0.patch @@ -0,0 +1,26 @@ +From 4d5e724a78803ed18033f04e7ffec6c8ea3bc922 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 7 Sep 2017 14:37:06 +0200 +Subject: [PATCH] fix compilation after commit + 382877acc6c029e59e359a076d203ca03b4b9e9e + +It turns out that explicit #warning macros work as explicit errors with -Werror. + +Related: #1447937 +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index def9fe5ce..ee147e28e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -188,7 +188,7 @@ CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ + -Wno-missing-field-initializers \ + -Wno-unused-result \ + -Werror \ +- -Wno-error=maybe-uninitialized \ ++ -Wno-error=maybe-uninitialized -Wno-error=cpp \ + -Wdate-time \ + -Wnested-externs \ + -ffast-math \ diff --git a/SOURCES/0508-shared-cgroup-utils-_CGROUP_CONTROLLER_MASK_ALL-does.patch b/SOURCES/0508-shared-cgroup-utils-_CGROUP_CONTROLLER_MASK_ALL-does.patch deleted file mode 100644 index efa1b99..0000000 --- a/SOURCES/0508-shared-cgroup-utils-_CGROUP_CONTROLLER_MASK_ALL-does.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 839a1935c5433fe973008f231aeb247df0344eca Mon Sep 17 00:00:00 2001 -From: Lukas Nykryn -Date: Tue, 9 Jan 2018 12:59:19 +0100 -Subject: [PATCH] shared/cgroup-utils: _CGROUP_CONTROLLER_MASK_ALL does not - cover CGROUP_PIDS - -7d44d0d43465892d4753ff50592588f49d56cf95 added a CGROUP_PIDS but -did not bump _CGROUP_CONTROLLER_MASK_ALL. - -RHEL-only -Resolves: #1532586 ---- - src/shared/cgroup-util.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h -index 31bd8d311..e76cd334d 100644 ---- a/src/shared/cgroup-util.h -+++ b/src/shared/cgroup-util.h -@@ -36,7 +36,7 @@ typedef enum CGroupControllerMask { - CGROUP_MEMORY = 8, - CGROUP_DEVICE = 16, - CGROUP_PIDS = 32, -- _CGROUP_CONTROLLER_MASK_ALL = 31 -+ _CGROUP_CONTROLLER_MASK_ALL = 63 - } CGroupControllerMask; - - /* diff --git a/SOURCES/0509-Redefine-32bit-time_t-format-to-signed.patch b/SOURCES/0509-Redefine-32bit-time_t-format-to-signed.patch new file mode 100644 index 0000000..23e502c --- /dev/null +++ b/SOURCES/0509-Redefine-32bit-time_t-format-to-signed.patch @@ -0,0 +1,37 @@ +From 10a1adc237ada061f557a7ae422456aa7d8c2c05 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 7 Sep 2017 14:41:09 +0200 +Subject: [PATCH] Redefine 32bit time_t format to signed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It seems that it is signed both on i386 and arm. + +Avoids a stupid gcc warning on arm: + +src/udev/udevadm-monitor.c: In function ‘print_device’: +src/udev/udevadm-monitor.c:44:16: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 3 has type ‘__time_t {aka long int}’ [-Wformat=] + printf("%-6s[%"PRI_TIME".%06ld] %-8s %s (%s)\n", + ^ + +(cherry picked from commit 6307c39b94344b901c1d6e0df7ee58644a8809bf) + +Related: #1447937 +--- + src/shared/util.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/util.h b/src/shared/util.h +index f1b6c348f..80ad18c0a 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -72,7 +72,7 @@ + #if SIZEOF_TIME_T == 8 + # define PRI_TIME PRIi64 + #elif SIZEOF_TIME_T == 4 +-# define PRI_TIME PRIu32 ++# define PRI_TIME "li" + #else + # error Unknown time_t size + #endif diff --git a/SOURCES/0509-core-execute-fix-fork-fail-handling-in-exec_spawn.patch b/SOURCES/0509-core-execute-fix-fork-fail-handling-in-exec_spawn.patch deleted file mode 100644 index 55607c8..0000000 --- a/SOURCES/0509-core-execute-fix-fork-fail-handling-in-exec_spawn.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 7ebf4a0faffecb3a0c8abe8bea47502044038d66 Mon Sep 17 00:00:00 2001 -From: lc85446 -Date: Thu, 26 Nov 2015 11:46:40 +0800 -Subject: [PATCH] core:execute: fix fork() fail handling in exec_spawn() - -If pid < 0 after fork(), 0 is always returned because r = -exec_context_load_environment() has exited successfully. - -This will make the caller of exec_spawn() not able to handle -the fork() error case and make systemd abort assert() possibly. - -Cherry-picked from: 74129a127676e4f0edac0db4296c103e76ec6694 -Resolves: #1437114 ---- - src/core/execute.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/core/execute.c b/src/core/execute.c -index 4265b9c34..e68276973 100644 ---- a/src/core/execute.c -+++ b/src/core/execute.c -@@ -1977,7 +1977,7 @@ int exec_spawn(ExecCommand *command, - NULL); - pid = fork(); - if (pid < 0) -- return log_unit_error_errno(params->unit_id, r, "Failed to fork: %m"); -+ return log_unit_error_errno(params->unit_id, errno, "Failed to fork: %m"); - - if (pid == 0) { - int exit_status; diff --git a/SOURCES/0510-journal-remove-error-check-that-never-happens.patch b/SOURCES/0510-journal-remove-error-check-that-never-happens.patch deleted file mode 100644 index fb5110a..0000000 --- a/SOURCES/0510-journal-remove-error-check-that-never-happens.patch +++ /dev/null @@ -1,53 +0,0 @@ -From cc8cc45e4b7799ac1dad7701de2df3db4fbb790c Mon Sep 17 00:00:00 2001 -From: Thomas Hindoe Paaboel Andersen -Date: Fri, 14 Aug 2015 23:40:27 +0200 -Subject: [PATCH] journal: remove error check that never happens - -remove_directory will always return 0 so this can never happen. -Besides that, d->path and d are freed so we would end up with -a null pointer dereference anyway. - -(cherry picked from commit b2b46f91dbb71676cb981907c68521e4b1e80af1) - -Related: #1465759 ---- - src/journal/sd-journal.c | 12 +++--------- - 1 file changed, 3 insertions(+), 9 deletions(-) - -diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c -index 72f312b67..3749f9e89 100644 ---- a/src/journal/sd-journal.c -+++ b/src/journal/sd-journal.c -@@ -1487,7 +1487,7 @@ static int add_root_directory(sd_journal *j, const char *p) { - return 0; - } - --static int remove_directory(sd_journal *j, Directory *d) { -+static void remove_directory(sd_journal *j, Directory *d) { - assert(j); - - if (d->wd > 0) { -@@ -1506,8 +1506,6 @@ static int remove_directory(sd_journal *j, Directory *d) { - - free(d->path); - free(d); -- -- return 0; - } - - static int add_search_paths(sd_journal *j) { -@@ -2145,12 +2143,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { - - /* Event for a subdirectory */ - -- if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) { -- r = remove_directory(j, d); -- if (r < 0) -- log_debug_errno(r, "Failed to remove directory %s: %m", d->path); -- } -- -+ if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) -+ remove_directory(j, d); - - } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) { - diff --git a/SOURCES/0510-sd-bus-bus-kernel.c-fix-format-errors-on-ppc64le.patch b/SOURCES/0510-sd-bus-bus-kernel.c-fix-format-errors-on-ppc64le.patch new file mode 100644 index 0000000..360bd21 --- /dev/null +++ b/SOURCES/0510-sd-bus-bus-kernel.c-fix-format-errors-on-ppc64le.patch @@ -0,0 +1,43 @@ +From b5b6f19445904feff90d6b2f9651ba51ef405144 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 7 Sep 2017 14:43:07 +0200 +Subject: [PATCH] sd-bus/bus-kernel.c: fix format errors on ppc64le + +RHEL-only + +Related: #1447937 +--- + src/libsystemd/sd-bus/bus-kernel.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c +index e90ee449d..d1c90858e 100644 +--- a/src/libsystemd/sd-bus/bus-kernel.c ++++ b/src/libsystemd/sd-bus/bus-kernel.c +@@ -763,7 +763,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { + break; + + default: +- log_debug("Got unknown field from kernel %llu", d->type); ++ log_debug("Got unknown field from kernel %llu", (unsigned long long) d->type); + } + } + +@@ -1244,7 +1244,7 @@ static int translate_id_change( + assert(k); + assert(d); + +- sprintf(owner, ":1.%llu", d->id_change.id); ++ sprintf(owner, ":1.%llu", (unsigned long long) d->id_change.id); + + return push_name_owner_changed( + bus, owner, +@@ -1317,7 +1317,7 @@ static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) { + return -EBADMSG; + found = d; + } else +- log_debug("Got unknown field from kernel %llu", d->type); ++ log_debug("Got unknown field from kernel %llu", (unsigned long long) d->type); + } + + if (!found) { diff --git a/SOURCES/0511-sd-journal-various-clean-ups-and-modernizations.patch b/SOURCES/0511-sd-journal-various-clean-ups-and-modernizations.patch deleted file mode 100644 index caed1b5..0000000 --- a/SOURCES/0511-sd-journal-various-clean-ups-and-modernizations.patch +++ /dev/null @@ -1,503 +0,0 @@ -From ee0e6e54479f8ad1991e531bb1e931b696d67aaf Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Mon, 2 Nov 2015 23:14:30 +0100 -Subject: [PATCH] sd-journal: various clean-ups and modernizations - -- Always print a debug log message about files and directories we cannot - open right when it happens instead of the caller, thus reducing the - number of places where we need to generate the debug message. - -- Always push the errors we encounter immediately into the error set, - when we run into them, instead of in the caller. Thus, we never forget - to push them in. - -- Use stack instead of heap memory where we can. - -- Make remove_file() void, since it cannot fail anyway and always - returned 0. - -- Make local machine check of journal directories explicit in a - function, to make things more readable. - -- Port to all directory listing loops FOREACH_DIRENT_ALL() - -- sd-daemon is library code, hence never log at higher log levels than - LOG_DEBUG. - -(cherry picked from commit d617408ecbe69db69aefddfcb10a6c054ea46ba0) - -Related: #1465759 ---- - src/journal/sd-journal.c | 242 ++++++++++++++++++++++------------------------- - 1 file changed, 111 insertions(+), 131 deletions(-) - -diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c -index 3749f9e89..9895d9608 100644 ---- a/src/journal/sd-journal.c -+++ b/src/journal/sd-journal.c -@@ -1171,6 +1171,8 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) { - } - - static bool file_type_wanted(int flags, const char *filename) { -+ assert(filename); -+ - if (!endswith(filename, ".journal") && !endswith(filename, ".journal~")) - return false; - -@@ -1195,7 +1197,7 @@ static bool file_type_wanted(int flags, const char *filename) { - - static int add_any_file(sd_journal *j, const char *path) { - JournalFile *f = NULL; -- int r; -+ int r, k; - - assert(j); - assert(path); -@@ -1204,20 +1206,23 @@ static int add_any_file(sd_journal *j, const char *path) { - return 0; - - if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { -- log_warning("Too many open journal files, not adding %s.", path); -- return set_put_error(j, -ETOOMANYREFS); -+ log_debug("Too many open journal files, not adding %s.", path); -+ r = -ETOOMANYREFS; -+ goto fail; - } - - r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f); -- if (r < 0) -- return r; -+ if (r < 0) { -+ log_debug_errno(r, "Failed to open journal file %s: %m", path); -+ goto fail; -+ } - - /* journal_file_dump(f); */ - - r = ordered_hashmap_put(j->files, f->path, f); - if (r < 0) { - journal_file_close(f); -- return r; -+ goto fail; - } - - log_debug("File %s added.", f->path); -@@ -1227,10 +1232,17 @@ static int add_any_file(sd_journal *j, const char *path) { - j->current_invalidate_counter ++; - - return 0; -+ -+fail: -+ k = set_put_error(j, r); -+ if (k < 0) -+ return k; -+ -+ return r; - } - - static int add_file(sd_journal *j, const char *prefix, const char *filename) { -- char *path = NULL; -+ const char *path; - - assert(j); - assert(prefix); -@@ -1250,24 +1262,20 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { - return add_any_file(j, path); - } - --static int remove_file(sd_journal *j, const char *prefix, const char *filename) { -- _cleanup_free_ char *path; -+static void remove_file(sd_journal *j, const char *prefix, const char *filename) { -+ const char *path; - JournalFile *f; - - assert(j); - assert(prefix); - assert(filename); - -- path = strjoin(prefix, "/", filename, NULL); -- if (!path) -- return -ENOMEM; -- -+ path = strjoina(prefix, "/", filename); - f = ordered_hashmap_get(j->files, path); - if (!f) -- return 0; -+ return; - - remove_file_real(j, f); -- return 0; - } - - static void remove_file_real(sd_journal *j, JournalFile *f) { -@@ -1296,12 +1304,27 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { - j->current_invalidate_counter ++; - } - -+static int dirname_is_machine_id(const char *fn) { -+ sd_id128_t id, machine; -+ int r; -+ -+ r = sd_id128_get_machine(&machine); -+ if (r < 0) -+ return r; -+ -+ r = sd_id128_from_string(fn, &id); -+ if (r < 0) -+ return r; -+ -+ return sd_id128_equal(id, machine); -+} -+ - static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { - _cleanup_free_ char *path = NULL; -- int r; - _cleanup_closedir_ DIR *d = NULL; -- sd_id128_t id, mid; -+ struct dirent *de = NULL; - Directory *m; -+ int r, k; - - assert(j); - assert(prefix); -@@ -1310,35 +1333,36 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) - log_debug("Considering %s/%s.", prefix, dirname); - - if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && -- (sd_id128_from_string(dirname, &id) < 0 || -- sd_id128_get_machine(&mid) < 0 || -- !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run")))) -+ !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run"))) - return 0; - - path = strjoin(prefix, "/", dirname, NULL); -- if (!path) -- return -ENOMEM; -+ if (!path) { -+ r = -ENOMEM; -+ goto fail; -+ } - - d = opendir(path); - if (!d) { -- log_debug_errno(errno, "Failed to open %s: %m", path); -- if (errno == ENOENT) -- return 0; -- return -errno; -+ r = log_debug_errno(errno, "Failed to open directory %s: %m", path); -+ goto fail; - } - - m = hashmap_get(j->directories_by_path, path); - if (!m) { - m = new0(Directory, 1); -- if (!m) -- return -ENOMEM; -+ if (!m) { -+ r = -ENOMEM; -+ goto fail; -+ } - - m->is_root = false; - m->path = path; - - if (hashmap_put(j->directories_by_path, m->path, m) < 0) { - free(m); -- return -ENOMEM; -+ r = -ENOMEM; -+ goto fail; - } - - path = NULL; /* avoid freeing in cleanup */ -@@ -1360,41 +1384,30 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) - inotify_rm_watch(j->inotify_fd, m->wd); - } - -- for (;;) { -- struct dirent *de; -- -- errno = 0; -- de = readdir(d); -- if (!de && errno != 0) { -- r = -errno; -- log_debug_errno(errno, "Failed to read directory %s: %m", m->path); -- return r; -- } -- if (!de) -- break; -+ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { - - if (dirent_is_file_with_suffix(de, ".journal") || -- dirent_is_file_with_suffix(de, ".journal~")) { -- r = add_file(j, m->path, de->d_name); -- if (r < 0) { -- log_debug_errno(r, "Failed to add file %s/%s: %m", -- m->path, de->d_name); -- r = set_put_error(j, r); -- if (r < 0) -- return r; -- } -- } -+ dirent_is_file_with_suffix(de, ".journal~")) -+ (void) add_file(j, m->path, de->d_name); - } - - check_network(j, dirfd(d)); - - return 0; -+ -+fail: -+ k = set_put_error(j, r); -+ if (k < 0) -+ return k; -+ -+ return r; - } - --static int add_root_directory(sd_journal *j, const char *p) { -+static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { - _cleanup_closedir_ DIR *d = NULL; -+ struct dirent *de; - Directory *m; -- int r; -+ int r, k; - - assert(j); - assert(p); -@@ -1407,26 +1420,35 @@ static int add_root_directory(sd_journal *j, const char *p) { - p = strjoina(j->prefix, p); - - d = opendir(p); -- if (!d) -- return -errno; -+ if (!d) { -+ if (errno == ENOENT && missing_ok) -+ return 0; -+ -+ r = log_debug_errno(errno, "Failed to open root directory %s: %m", p); -+ goto fail; -+ } - - m = hashmap_get(j->directories_by_path, p); - if (!m) { - m = new0(Directory, 1); -- if (!m) -- return -ENOMEM; -+ if (!m) { -+ r = -ENOMEM; -+ goto fail; -+ } - - m->is_root = true; - m->path = strdup(p); - if (!m->path) { - free(m); -- return -ENOMEM; -+ r = -ENOMEM; -+ goto fail; - } - - if (hashmap_put(j->directories_by_path, m->path, m) < 0) { - free(m->path); - free(m); -- return -ENOMEM; -+ r = -ENOMEM; -+ goto fail; - } - - j->current_invalidate_counter ++; -@@ -1449,42 +1471,27 @@ static int add_root_directory(sd_journal *j, const char *p) { - if (j->no_new_files) - return 0; - -- for (;;) { -- struct dirent *de; -+ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { - sd_id128_t id; - -- errno = 0; -- de = readdir(d); -- if (!de && errno != 0) { -- r = -errno; -- log_debug_errno(errno, "Failed to read directory %s: %m", m->path); -- return r; -- } -- if (!de) -- break; -- - if (dirent_is_file_with_suffix(de, ".journal") || -- dirent_is_file_with_suffix(de, ".journal~")) { -- r = add_file(j, m->path, de->d_name); -- if (r < 0) { -- log_debug_errno(r, "Failed to add file %s/%s: %m", -- m->path, de->d_name); -- r = set_put_error(j, r); -- if (r < 0) -- return r; -- } -- } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) && -- sd_id128_from_string(de->d_name, &id) >= 0) { -- -- r = add_directory(j, m->path, de->d_name); -- if (r < 0) -- log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name); -- } -+ dirent_is_file_with_suffix(de, ".journal~")) -+ (void) add_file(j, m->path, de->d_name); -+ else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) && -+ sd_id128_from_string(de->d_name, &id) >= 0) -+ (void) add_directory(j, m->path, de->d_name); - } - - check_network(j, dirfd(d)); - - return 0; -+ -+fail: -+ k = set_put_error(j, r); -+ if (k < 0) -+ return k; -+ -+ return r; - } - - static void remove_directory(sd_journal *j, Directory *d) { -@@ -1509,8 +1516,8 @@ static void remove_directory(sd_journal *j, Directory *d) { - } - - static int add_search_paths(sd_journal *j) { -- int r; -- const char search_paths[] = -+ -+ static const char search_paths[] = - "/run/log/journal\0" - "/var/log/journal\0"; - const char *p; -@@ -1520,14 +1527,8 @@ static int add_search_paths(sd_journal *j) { - /* We ignore most errors here, since the idea is to only open - * what's actually accessible, and ignore the rest. */ - -- NULSTR_FOREACH(p, search_paths) { -- r = add_root_directory(j, p); -- if (r < 0 && r != -ENOENT) { -- r = set_put_error(j, r); -- if (r < 0) -- return r; -- } -- } -+ NULSTR_FOREACH(p, search_paths) -+ (void) add_root_directory(j, p, true); - - return 0; - } -@@ -1551,17 +1552,14 @@ static int add_current_paths(sd_journal *j) { - if (!dir) - return -ENOMEM; - -- r = add_root_directory(j, dir); -- if (r < 0) { -- set_put_error(j, r); -+ r = add_root_directory(j, dir, true); -+ if (r < 0) - return r; -- } - } - - return 0; - } - -- - static int allocate_inotify(sd_journal *j) { - assert(j); - -@@ -1689,11 +1687,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f - if (!j) - return -ENOMEM; - -- r = add_root_directory(j, path); -- if (r < 0) { -- set_put_error(j, r); -+ r = add_root_directory(j, path, false); -+ if (r < 0) - goto fail; -- } - - *ret = j; - return 0; -@@ -1718,10 +1714,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla - - STRV_FOREACH(path, paths) { - r = add_any_file(j, *path); -- if (r < 0) { -- log_error_errno(r, "Failed to open %s: %m", *path); -+ if (r < 0) - goto fail; -- } - } - - j->no_new_files = true; -@@ -2061,7 +2055,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) { - if (j->no_new_files) - r = add_current_paths(j); - else if (j->path) -- r = add_root_directory(j, j->path); -+ r = add_root_directory(j, j->path, true); - else - r = add_search_paths(j); - if (r < 0) -@@ -2108,7 +2102,6 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { - - static void process_inotify_event(sd_journal *j, struct inotify_event *e) { - Directory *d; -- int r; - - assert(j); - assert(e); -@@ -2124,20 +2117,10 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { - - /* Event for a journal file */ - -- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { -- r = add_file(j, d->path, e->name); -- if (r < 0) { -- log_debug_errno(r, "Failed to add file %s/%s: %m", -- d->path, e->name); -- set_put_error(j, r); -- } -- -- } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) { -- -- r = remove_file(j, d->path, e->name); -- if (r < 0) -- log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name); -- } -+ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) -+ (void) add_file(j, d->path, e->name); -+ else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) -+ remove_file(j, d->path, e->name); - - } else if (!d->is_root && e->len == 0) { - -@@ -2150,11 +2133,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { - - /* Event for root directory */ - -- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { -- r = add_directory(j, d->path, e->name); -- if (r < 0) -- log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name); -- } -+ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) -+ (void) add_directory(j, d->path, e->name); - } - - return; -@@ -2163,7 +2143,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { - if (e->mask & IN_IGNORED) - return; - -- log_warning("Unknown inotify event."); -+ log_debug("Unknown inotify event."); - } - - static int determine_change(sd_journal *j) { diff --git a/SOURCES/0511-tmpfiles-with-e-don-t-attempt-to-set-permissions-whe.patch b/SOURCES/0511-tmpfiles-with-e-don-t-attempt-to-set-permissions-whe.patch new file mode 100644 index 0000000..be7b3bb --- /dev/null +++ b/SOURCES/0511-tmpfiles-with-e-don-t-attempt-to-set-permissions-whe.patch @@ -0,0 +1,65 @@ +From 797dafce1bb9c3bb16da043f654391dc29075a1a Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 28 Aug 2017 17:33:24 +0200 +Subject: [PATCH] tmpfiles: with "e" don't attempt to set permissions when file + doesn't exist + +tmpfiles.d option "e" when run through systemd-tmpfiles --create should +apply configured permissions (uid,gid) only to already existing +files. When file doesn't exist we bail out with error. Instead we should +silently ignore non-existing files. + +$ useradd test +$ cat /etc/tmpfiles.d/foobar.conf +e /tmp/test - test test 1d +$ ls -l /tmp/test +ls: cannot access '/tmp/test': No such file or directory + +Before: +$ systemd-tmpfiles --create /etc/tmpfiles.d/foobar.conf +Adjusting owner and mode for /tmp/test failed: No such file or directory +$ echo $? +1 + +After: +$ systemd-tmpfiles --create /etc/tmpfiles.d/foobar.conf +$ echo $? +0 + +(cherry picked from commit 3caf791a1702c97b99d2647c9d465af404f2913d) + +Conflicts: + src/tmpfiles/tmpfiles.c + +Resolves: #1445732 +--- + src/tmpfiles/tmpfiles.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index df7676b57..ed35b8cf0 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -585,8 +585,20 @@ static int path_set_perms(Item *i, const char *path) { + * 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 (fd < 0) { ++ int level = LOG_ERR, r = -errno; ++ ++ /* Option "e" operates only on existing objects. Do not ++ * print errors about non-existent files or directories */ ++ if (i->type == EMPTY_DIRECTORY && errno == ENOENT) { ++ level = LOG_DEBUG; ++ r = 0; ++ } ++ ++ log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path); ++ ++ return r; ++ } + + if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0) + return log_error_errno(errno, "Failed to fstat() file %s: %m", path); diff --git a/SOURCES/0512-journalctl-continue-operation-even-if-we-run-into-an.patch b/SOURCES/0512-journalctl-continue-operation-even-if-we-run-into-an.patch deleted file mode 100644 index 5560ea6..0000000 --- a/SOURCES/0512-journalctl-continue-operation-even-if-we-run-into-an.patch +++ /dev/null @@ -1,35 +0,0 @@ -From f5a2a7b3630d0ba9a25f8a81cdeaf5336b745e3e Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Mon, 2 Nov 2015 23:13:01 +0100 -Subject: [PATCH] journalctl: continue operation, even if we run into an - invalid file - -(cherry picked from commit 4f52b822b05c373f40fea1a41ae3ade5d5ff558e) - -Related: #1465759 ---- - src/journal/journalctl.c | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c -index c771cff8b..8c8379732 100644 ---- a/src/journal/journalctl.c -+++ b/src/journal/journalctl.c -@@ -1804,15 +1804,12 @@ static int access_check(sd_journal *j) { - SET_FOREACH(code, j->errors, it) { - int err; - -- err = -PTR_TO_INT(code); -- assert(err > 0); -+ err = abs(PTR_TO_INT(code)); - - if (err == EACCES) - continue; - -- log_warning_errno(err, "Error was encountered while opening journal files: %m"); -- if (r == 0) -- r = -err; -+ log_warning_errno(err, "An error was encountered while opening journal files, ignoring: %m"); - } - - return r; diff --git a/SOURCES/0512-units-introduce-getty-pre.target-6667.patch b/SOURCES/0512-units-introduce-getty-pre.target-6667.patch new file mode 100644 index 0000000..3d298ba --- /dev/null +++ b/SOURCES/0512-units-introduce-getty-pre.target-6667.patch @@ -0,0 +1,112 @@ +From d538b6082216f4867b4a50c8009abe2462aafbf4 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 31 Aug 2017 11:20:14 +0200 +Subject: [PATCH] units: introduce getty-pre.target (#6667) + +This new target is a passive unit, hence it is supposed to be pulled in +to the transaction by the service that wants to block login on the +console (e.g. text version of initial-setup). Now both getty and +serial-getty are ordered after this target. + +https://lists.freedesktop.org/archives/systemd-devel/2015-July/033754.html + +(cherry picked from commit 175902541852fb9207f6e532d8da48c9a102340c) + +Conflicts: + units/meson.build + +Resolves: #1173080 +--- + Makefile.am | 1 + + man/systemd.special.xml | 12 ++++++++++++ + units/getty-pre.target | 11 +++++++++++ + units/getty@.service.m4 | 2 +- + units/serial-getty@.service.m4 | 2 +- + 5 files changed, 26 insertions(+), 2 deletions(-) + create mode 100644 units/getty-pre.target + +diff --git a/Makefile.am b/Makefile.am +index e9ceac98a..7c58fd050 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -462,6 +462,7 @@ dist_systemunit_DATA = \ + units/sysinit.target \ + units/basic.target \ + units/getty.target \ ++ units/getty-pre.target \ + units/halt.target \ + units/kexec.target \ + units/local-fs.target \ +diff --git a/man/systemd.special.xml b/man/systemd.special.xml +index 553197d66..eb464f9f8 100644 +--- a/man/systemd.special.xml ++++ b/man/systemd.special.xml +@@ -61,6 +61,7 @@ + exit.target, + final.target, + getty.target, ++ getty-pre.target, + graphical.target, + halt.target, + hibernate.target, +@@ -216,6 +217,17 @@ + + + ++ ++ getty-pre.target ++ ++ A special passive target unit. Users of this target ++ are expected to pull it in the boot transaction via ++ a dependency (e.g. Wants=). Order your ++ unit before this unit if you want to make use of the console ++ just before getty is started. ++ ++ ++ + + graphical.target + +diff --git a/units/getty-pre.target b/units/getty-pre.target +new file mode 100644 +index 000000000..f6c78b6c2 +--- /dev/null ++++ b/units/getty-pre.target +@@ -0,0 +1,11 @@ ++# This file is part of systemd. ++# ++# systemd is free software; you can redistribute it and/or modify it ++# under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++ ++[Unit] ++Description=Login Prompts (Pre) ++Documentation=man:systemd.special(7) man:systemd-getty-generator(8) ++Documentation=http://0pointer.de/blog/projects/serial-console.html +diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 +index 46164ab9d..ad4bf2103 100644 +--- a/units/getty@.service.m4 ++++ b/units/getty@.service.m4 +@@ -9,7 +9,7 @@ + Description=Getty on %I + Documentation=man:agetty(8) man:systemd-getty-generator(8) + Documentation=http://0pointer.de/blog/projects/serial-console.html +-After=systemd-user-sessions.service plymouth-quit-wait.service ++After=systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target + m4_ifdef(`HAVE_SYSV_COMPAT', + After=rc-local.service + )m4_dnl +diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4 +index 4522d0d2b..6802333f7 100644 +--- a/units/serial-getty@.service.m4 ++++ b/units/serial-getty@.service.m4 +@@ -10,7 +10,7 @@ Description=Serial Getty on %I + Documentation=man:agetty(8) man:systemd-getty-generator(8) + Documentation=http://0pointer.de/blog/projects/serial-console.html + BindsTo=dev-%i.device +-After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service ++After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target + m4_ifdef(`HAVE_SYSV_COMPAT', + After=rc-local.service + )m4_dnl diff --git a/SOURCES/0513-journalctl-when-we-fail-to-open-a-journal-file-print.patch b/SOURCES/0513-journalctl-when-we-fail-to-open-a-journal-file-print.patch deleted file mode 100644 index 5833c08..0000000 --- a/SOURCES/0513-journalctl-when-we-fail-to-open-a-journal-file-print.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 8a5944217f444929ba6a4124a4ee7fbd2c5a3fc3 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Mon, 2 Nov 2015 23:37:05 +0100 -Subject: [PATCH] journalctl: when we fail to open a journal file, print why - -When we enumerate journal files and encounter an invalid one, remember -which this, and show it to the user. - -Note the possibly slightly surprising logic here: we store only one path -per error code. This means we show all error kinds but not every actual -error we encounter. This has the benefit of not requiring us to keep a -potentially unbounded list of errors with their sources around, but can -still provide a pretty complete overview on the errors we encountered. - -Fixes #1669. - -(cherry picked from commit 5768d2594940668506bb4cafa078f654cc20dc5a) - -Resolves: #1465759 ---- - src/journal/journal-internal.h | 2 +- - src/journal/journalctl.c | 27 ++++++++++++++++++----- - src/journal/sd-journal.c | 49 ++++++++++++++++++++++++++++++++++-------- - 3 files changed, 63 insertions(+), 15 deletions(-) - -diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h -index 115d7776d..eb23ac28a 100644 ---- a/src/journal/journal-internal.h -+++ b/src/journal/journal-internal.h -@@ -123,7 +123,7 @@ struct sd_journal { - Hashmap *directories_by_path; - Hashmap *directories_by_wd; - -- Set *errors; -+ Hashmap *errors; - }; - - char *journal_make_match_string(sd_journal *j); -diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c -index 8c8379732..0be70764e 100644 ---- a/src/journal/journalctl.c -+++ b/src/journal/journalctl.c -@@ -1783,33 +1783,50 @@ static int access_check_var_log_journal(sd_journal *j) { - static int access_check(sd_journal *j) { - Iterator it; - void *code; -+ char *path; - int r = 0; - - assert(j); - -- if (set_isempty(j->errors)) { -+ if (hashmap_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))) { -+ if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) { - (void) access_check_var_log_journal(j); - - 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) { -+ HASHMAP_FOREACH_KEY(path, code, j->errors, it) { - int err; - - err = abs(PTR_TO_INT(code)); - -- if (err == EACCES) -+ switch (err) { -+ case EACCES: - continue; - -- log_warning_errno(err, "An error was encountered while opening journal files, ignoring: %m"); -+ case ENODATA: -+ log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path); -+ break; -+ -+ case EPROTONOSUPPORT: -+ log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path); -+ break; -+ -+ case EBADMSG: -+ log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path); -+ break; -+ -+ default: -+ log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path); -+ break; -+ } - } - - return r; -diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c -index 9895d9608..14b65cfed 100644 ---- a/src/journal/sd-journal.c -+++ b/src/journal/sd-journal.c -@@ -62,19 +62,46 @@ static bool journal_pid_changed(sd_journal *j) { - return j->original_pid != getpid(); - } - --/* We return an error here only if we didn't manage to -- memorize the real error. */ --static int set_put_error(sd_journal *j, int r) { -+static int journal_put_error(sd_journal *j, int r, const char *path) { -+ char *copy; - int k; - -+ /* Memorize an error we encountered, and store which -+ * file/directory it was generated from. Note that we store -+ * only *one* path per error code, as the error code is the -+ * key into the hashmap, and the path is the value. This means -+ * we keep track only of all error kinds, but not of all error -+ * locations. This has the benefit that the hashmap cannot -+ * grow beyond bounds. -+ * -+ * We return an error here only if we didn't manage to -+ * memorize the real error. */ -+ - if (r >= 0) - return r; - -- k = set_ensure_allocated(&j->errors, NULL); -+ k = hashmap_ensure_allocated(&j->errors, NULL); - if (k < 0) - return k; - -- return set_put(j->errors, INT_TO_PTR(r)); -+ if (path) { -+ copy = strdup(path); -+ if (!copy) -+ return -ENOMEM; -+ } else -+ copy = NULL; -+ -+ k = hashmap_put(j->errors, INT_TO_PTR(r), copy); -+ if (k < 0) { -+ free(copy); -+ -+ if (k == -EEXIST) -+ return 0; -+ -+ return k; -+ } -+ -+ return 0; - } - - static void detach_location(sd_journal *j) { -@@ -1234,7 +1261,7 @@ static int add_any_file(sd_journal *j, const char *path) { - return 0; - - fail: -- k = set_put_error(j, r); -+ k = journal_put_error(j, r, path); - if (k < 0) - return k; - -@@ -1396,7 +1423,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) - return 0; - - fail: -- k = set_put_error(j, r); -+ k = journal_put_error(j, r, path ?: dirname); - if (k < 0) - return k; - -@@ -1487,7 +1514,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { - return 0; - - fail: -- k = set_put_error(j, r); -+ k = journal_put_error(j, r, p); - if (k < 0) - return k; - -@@ -1732,6 +1759,7 @@ fail: - _public_ void sd_journal_close(sd_journal *j) { - Directory *d; - JournalFile *f; -+ char *p; - - if (!j) - return; -@@ -1759,10 +1787,13 @@ _public_ void sd_journal_close(sd_journal *j) { - mmap_cache_unref(j->mmap); - } - -+ while ((p = hashmap_steal_first(j->errors))) -+ free(p); -+ hashmap_free(j->errors); -+ - free(j->path); - free(j->prefix); - free(j->unique_field); -- set_free(j->errors); - free(j); - } - diff --git a/SOURCES/0513-units-order-container-and-console-getty-units-after-.patch b/SOURCES/0513-units-order-container-and-console-getty-units-after-.patch new file mode 100644 index 0000000..2f1eba6 --- /dev/null +++ b/SOURCES/0513-units-order-container-and-console-getty-units-after-.patch @@ -0,0 +1,40 @@ +From b10c083e9b9de46b54873780f73dce57fa1b6d4f Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 5 Sep 2017 14:53:25 +0200 +Subject: [PATCH] units: order container and console getty units after + getty-pre.target + +(cherry picked from commit 45e27532971ac84e835a2879df510a581f933fcd) + +Related: #1173080 +--- + units/console-getty.service.m4.in | 2 +- + units/container-getty@.service.m4.in | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/units/console-getty.service.m4.in b/units/console-getty.service.m4.in +index 413d94094..61ecf8951 100644 +--- a/units/console-getty.service.m4.in ++++ b/units/console-getty.service.m4.in +@@ -11,7 +11,7 @@ Documentation=man:agetty(8) + After=systemd-user-sessions.service plymouth-quit-wait.service + ConditionPathExists=/dev/console + m4_ifdef(`HAVE_SYSV_COMPAT', +-After=rc-local.service ++After=rc-local.service getty-pre.target + )m4_dnl + Before=getty.target + +diff --git a/units/container-getty@.service.m4.in b/units/container-getty@.service.m4.in +index e126f3a48..4395ef5ce 100644 +--- a/units/container-getty@.service.m4.in ++++ b/units/container-getty@.service.m4.in +@@ -10,7 +10,7 @@ Description=Container Getty on /dev/pts/%I + Documentation=man:agetty(8) man:machinectl(1) + After=systemd-user-sessions.service plymouth-quit-wait.service + m4_ifdef(`HAVE_SYSV_COMPAT', +-After=rc-local.service ++After=rc-local.service getty-pre.target + )m4_dnl + Before=getty.target + IgnoreOnIsolate=yes diff --git a/SOURCES/0514-log-never-log-into-foreign-fd-2-in-PID-1-or-its-pre-.patch b/SOURCES/0514-log-never-log-into-foreign-fd-2-in-PID-1-or-its-pre-.patch new file mode 100644 index 0000000..917239d --- /dev/null +++ b/SOURCES/0514-log-never-log-into-foreign-fd-2-in-PID-1-or-its-pre-.patch @@ -0,0 +1,76 @@ +From 5a7f49bb38bc1d7965d497e775b7cc8053b0c465 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 18 Aug 2017 10:17:22 +0200 +Subject: [PATCH] log: never log into foreign fd #2 in PID 1 or its + pre-execve() children + +(cherry picked from commit 48a601fe5de8aa0d89ba6dadde168769fa7ce992) +Resolves: #1420505 +--- + src/core/main.c | 11 +++++++++-- + src/shared/log.c | 7 ++++++- + src/shared/log.h | 1 + + 3 files changed, 16 insertions(+), 3 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index 37e3ea0ce..66393ed6a 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -1310,10 +1310,17 @@ int main(int argc, char *argv[]) { + log_show_color(isatty(STDERR_FILENO) > 0); + log_set_upgrade_syslog_to_journal(true); + +- /* Disable the umask logic */ +- if (getpid() == 1) ++ if (getpid() == 1) { ++ /* Disable the umask logic */ + umask(0); + ++ /* Always reopen /dev/console when running as PID 1 or one of its pre-execve() children. This is ++ * important so that we never end up logging to any foreign stderr, for example if we have to log in a ++ * child process right before execve()'ing the actual binary, at a point in time where socket ++ * activation stderr/stdout area already set up. */ ++ log_set_always_reopen_console(true); ++ } ++ + if (getpid() == 1 && detect_container(NULL) <= 0) { + + /* Running outside of a container as PID 1 */ +diff --git a/src/shared/log.c b/src/shared/log.c +index 646a1d638..349142030 100644 +--- a/src/shared/log.c ++++ b/src/shared/log.c +@@ -52,6 +52,7 @@ static bool show_color = false; + static bool show_location = false; + + static bool upgrade_syslog_to_journal = false; ++static bool always_reopen_console = false; + + /* Akin to glibc's __abort_msg; which is private and we hence cannot + * use here. */ +@@ -75,7 +76,7 @@ static int log_open_console(void) { + if (console_fd >= 0) + return 0; + +- if (getpid() == 1) { ++ if (always_reopen_console) { + console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (console_fd < 0) + return console_fd; +@@ -1061,3 +1062,7 @@ void log_received_signal(int level, const struct signalfd_siginfo *si) { + void log_set_upgrade_syslog_to_journal(bool b) { + upgrade_syslog_to_journal = b; + } ++ ++void log_set_always_reopen_console(bool b) { ++ always_reopen_console = b; ++} +diff --git a/src/shared/log.h b/src/shared/log.h +index 2889e1e77..3c9448f1a 100644 +--- a/src/shared/log.h ++++ b/src/shared/log.h +@@ -210,3 +210,4 @@ LogTarget log_target_from_string(const char *s) _pure_; + void log_received_signal(int level, const struct signalfd_siginfo *si); + + void log_set_upgrade_syslog_to_journal(bool b); ++void log_set_always_reopen_console(bool b); diff --git a/SOURCES/0514-sd-journal-properly-handle-inotify-queue-overflow.patch b/SOURCES/0514-sd-journal-properly-handle-inotify-queue-overflow.patch deleted file mode 100644 index 702ed0c..0000000 --- a/SOURCES/0514-sd-journal-properly-handle-inotify-queue-overflow.patch +++ /dev/null @@ -1,442 +0,0 @@ -From afb8109dd1968e6353dbdda13e6216e12f2dec03 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Mon, 12 Feb 2018 16:14:58 +0100 -Subject: [PATCH] sd-journal: properly handle inotify queue overflow - -This adds proper handling of IN_Q_OVERFLOW: when the inotify queue runs -over we'll reiterate all directories we are looking at. At the same time -we'll mark all files and directories we encounter that way with a -generation counter we first increased. All files and directories not -marked like this are then unloaded. - -With this logic we do the best when the inotify queue overflows: we -synchronize our in-memory state again with what's on disk. This -contains some refactoring of the directory logic, to share more code -between uuid directories and "root" directories and generally make -things a bit more readable by splitting things up into smaller bits. - -See: #7998 #8032 - -(cherry-picked from commit 858749f7312bd0adb5433075a92e1c35a2fb56ac) - -Resolves: #1540538 ---- - src/journal/journal-file.h | 2 + - src/journal/journal-internal.h | 2 + - src/journal/sd-journal.c | 237 ++++++++++++++++++++++++++++++++--------- - src/shared/path-util.c | 14 +++ - src/shared/path-util.h | 2 + - 5 files changed, 206 insertions(+), 51 deletions(-) - -diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h -index c74ad5fc5..dd8ef52d2 100644 ---- a/src/journal/journal-file.h -+++ b/src/journal/journal-file.h -@@ -121,6 +121,8 @@ typedef struct JournalFile { - - void *fsprg_seed; - size_t fsprg_seed_size; -+ -+ unsigned last_seen_generation; - #endif - } JournalFile; - -diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h -index eb23ac28a..999e9d8cb 100644 ---- a/src/journal/journal-internal.h -+++ b/src/journal/journal-internal.h -@@ -81,6 +81,7 @@ struct Directory { - char *path; - int wd; - bool is_root; -+ unsigned last_seen_generation; - }; - - struct sd_journal { -@@ -102,6 +103,7 @@ struct sd_journal { - int inotify_fd; - unsigned current_invalidate_counter, last_invalidate_counter; - usec_t last_process_usec; -+ unsigned generation; - - char *unique_field; - JournalFile *unique_file; -diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c -index 14b65cfed..9186f5188 100644 ---- a/src/journal/sd-journal.c -+++ b/src/journal/sd-journal.c -@@ -1229,8 +1229,16 @@ static int add_any_file(sd_journal *j, const char *path) { - assert(j); - assert(path); - -- if (ordered_hashmap_get(j->files, path)) -- return 0; -+ if (path) { -+ f = ordered_hashmap_get(j->files, path); -+ if (f) { -+ /* Mark this file as seen in this generation. This is used to GC old files in -+ * process_q_overflow() to detect journal files that are still and discern them from those who -+ * are gone. */ -+ f->last_seen_generation = j->generation; -+ return 0; -+ } -+ } - - if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { - log_debug("Too many open journal files, not adding %s.", path); -@@ -1252,6 +1260,8 @@ static int add_any_file(sd_journal *j, const char *path) { - goto fail; - } - -+ f->last_seen_generation = j->generation; -+ - log_debug("File %s added.", f->path); - - check_network(j, f->fd); -@@ -1346,10 +1356,96 @@ static int dirname_is_machine_id(const char *fn) { - return sd_id128_equal(id, machine); - } - -+static bool dirent_is_journal_file(const struct dirent *de) { -+ assert(de); -+ -+ if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) -+ return false; -+ -+ return endswith(de->d_name, ".journal") || -+ endswith(de->d_name, ".journal~"); -+} -+ -+static bool dirent_is_id128_subdir(const struct dirent *de) { -+ assert(de); -+ -+ if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN)) -+ return false; -+ -+ return id128_is_valid(de->d_name); -+} -+ -+static int directory_open(sd_journal *j, const char *path, DIR **ret) { -+ DIR *d; -+ -+ assert(j); -+ assert(path); -+ assert(ret); -+ -+ d = opendir(path); -+ if (!d) -+ return -errno; -+ -+ *ret = d; -+ return 0; -+} -+ -+static int add_directory(sd_journal *j, const char *prefix, const char *dirname); -+ -+static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) { -+ struct dirent *de; -+ -+ assert(j); -+ assert(m); -+ assert(d); -+ -+ FOREACH_DIRENT_ALL(de, d, goto fail) { -+ if (dirent_is_journal_file(de)) -+ (void) add_file(j, m->path, de->d_name); -+ -+ if (m->is_root && dirent_is_id128_subdir(de)) -+ (void) add_directory(j, m->path, de->d_name); -+ } -+ -+ return; -+ -+fail: -+ log_debug_errno(errno, "Failed to enumerate directory %s, ignoring: %m", m->path); -+} -+ -+static void directory_watch(sd_journal *j, Directory *m, int fd, uint32_t mask) { -+ int r; -+ -+ assert(j); -+ assert(m); -+ assert(fd >= 0); -+ -+ /* Watch this directory if that's enabled and if it not being watched yet. */ -+ -+ if (m->wd > 0) /* Already have a watch? */ -+ return; -+ if (j->inotify_fd < 0) /* Not watching at all? */ -+ return; -+ -+ m->wd = inotify_add_watch_fd(j->inotify_fd, fd, mask); -+ if (m->wd < 0) { -+ log_debug_errno(errno, "Failed to watch journal directory '%s', ignoring: %m", m->path); -+ return; -+ } -+ -+ r = hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m); -+ if (r == -EEXIST) -+ log_debug_errno(r, "Directory '%s' already being watched under a different path, ignoring: %m", m->path); -+ if (r < 0) { -+ log_debug_errno(r, "Failed to add watch for journal directory '%s' to hashmap, ignoring: %m", m->path); -+ (void) inotify_rm_watch(j->inotify_fd, m->wd); -+ m->wd = -1; -+ } -+} -+ - static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { - _cleanup_free_ char *path = NULL; - _cleanup_closedir_ DIR *d = NULL; -- struct dirent *de = NULL; - Directory *m; - int r, k; - -@@ -1357,7 +1453,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) - assert(prefix); - assert(dirname); - -- log_debug("Considering %s/%s.", prefix, dirname); -+ log_debug("Considering '%s/%s'.", prefix, dirname); - - if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && - !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run"))) -@@ -1369,9 +1465,9 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) - goto fail; - } - -- d = opendir(path); -- if (!d) { -- r = log_debug_errno(errno, "Failed to open directory %s: %m", path); -+ r = directory_open(j, path, &d); -+ if (r < 0) { -+ r = log_debug_errno(errno, "Failed to open directory '%s': %m", path); - goto fail; - } - -@@ -1398,25 +1494,17 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) - log_debug("Directory %s added.", m->path); - - } else if (m->is_root) -- return 0; -- -- if (m->wd <= 0 && j->inotify_fd >= 0) { -- -- m->wd = inotify_add_watch(j->inotify_fd, m->path, -- IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| -- IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM| -- IN_ONLYDIR); -+ return 0; /* Don't 'downgrade' from root directory */ - -- if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0) -- inotify_rm_watch(j->inotify_fd, m->wd); -- } -+ m->last_seen_generation = j->generation; - -- FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { -+ directory_watch(j, m, dirfd(d), -+ IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| -+ IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM| -+ IN_ONLYDIR); - -- if (dirent_is_file_with_suffix(de, ".journal") || -- dirent_is_file_with_suffix(de, ".journal~")) -- (void) add_file(j, m->path, de->d_name); -- } -+ if (!j->no_new_files) -+ directory_enumerate(j, m, d); - - check_network(j, dirfd(d)); - -@@ -1432,13 +1520,14 @@ fail: - - static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { - _cleanup_closedir_ DIR *d = NULL; -- struct dirent *de; - Directory *m; - int r, k; - - assert(j); - assert(p); - -+ log_debug("Considering root directory '%s'.", p); -+ - if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) && - !path_startswith(p, "/run")) - return -EINVAL; -@@ -1446,12 +1535,11 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { - if (j->prefix) - p = strjoina(j->prefix, p); - -- d = opendir(p); -- if (!d) { -- if (errno == ENOENT && missing_ok) -- return 0; -- -- r = log_debug_errno(errno, "Failed to open root directory %s: %m", p); -+ r = directory_open(j, p, &d); -+ if (r == -ENOENT && missing_ok) -+ return 0; -+ if (r < 0) { -+ log_debug_errno(r, "Failed to open root directory %s: %m", p); - goto fail; - } - -@@ -1495,19 +1583,12 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { - inotify_rm_watch(j->inotify_fd, m->wd); - } - -- if (j->no_new_files) -- return 0; -- -- FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { -- sd_id128_t id; -+ directory_watch(j, m, dirfd(d), -+ IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| -+ IN_ONLYDIR); - -- if (dirent_is_file_with_suffix(de, ".journal") || -- dirent_is_file_with_suffix(de, ".journal~")) -- (void) add_file(j, m->path, de->d_name); -- else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) && -- sd_id128_from_string(de->d_name, &id) >= 0) -- (void) add_directory(j, m->path, de->d_name); -- } -+ if (!j->no_new_files) -+ directory_enumerate(j, m, d); - - check_network(j, dirfd(d)); - -@@ -2068,6 +2149,18 @@ _public_ void sd_journal_restart_data(sd_journal *j) { - j->current_field = 0; - } - -+static int reiterate_all_paths(sd_journal *j) { -+ assert(j); -+ -+ if (j->no_new_files) -+ return add_current_paths(j); -+ -+ if (j->path) -+ return add_root_directory(j, j->path, true); -+ -+ return add_search_paths(j); -+} -+ - _public_ int sd_journal_get_fd(sd_journal *j) { - int r; - -@@ -2081,15 +2174,11 @@ _public_ int sd_journal_get_fd(sd_journal *j) { - if (r < 0) - return r; - -- /* Iterate through all dirs again, to add them to the -- * inotify */ -- if (j->no_new_files) -- r = add_current_paths(j); -- else if (j->path) -- r = add_root_directory(j, j->path, true); -- else -- r = add_search_paths(j); -- if (r < 0) -+ log_debug("Reiterating files to get inotify watches established."); -+ -+ /* Iterate through all dirs again, to add them to the inotify */ -+ r = reiterate_all_paths(j); -+ if (r < 0) - return r; - - return j->inotify_fd; -@@ -2131,12 +2220,58 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { - return 1; - } - -+static void process_q_overflow(sd_journal *j) { -+ JournalFile *f; -+ Directory *m; -+ Iterator i; -+ -+ assert(j); -+ -+ /* When the inotify queue overruns we need to enumerate and re-validate all journal files to bring our list -+ * back in sync with what's on disk. For this we pick a new generation counter value. It'll be assigned to all -+ * journal files we encounter. All journal files and all directories that don't carry it after reenumeration -+ * are subject for unloading. */ -+ -+ log_debug("Inotify queue overrun, reiterating everything."); -+ -+ j->generation++; -+ (void) reiterate_all_paths(j); -+ -+ ORDERED_HASHMAP_FOREACH(f, j->files, i) { -+ -+ if (f->last_seen_generation == j->generation) -+ continue; -+ -+ log_debug("File '%s' hasn't been seen in this enumeration, removing.", f->path); -+ remove_file_real(j, f); -+ } -+ -+ HASHMAP_FOREACH(m, j->directories_by_path, i) { -+ -+ if (m->last_seen_generation == j->generation) -+ continue; -+ -+ if (m->is_root) /* Never GC root directories */ -+ continue; -+ -+ log_debug("Directory '%s' hasn't been seen in this enumeration, removing.", f->path); -+ remove_directory(j, m); -+ } -+ -+ log_debug("Reiteration complete."); -+} -+ - static void process_inotify_event(sd_journal *j, struct inotify_event *e) { - Directory *d; - - assert(j); - assert(e); - -+ if (e->mask & IN_Q_OVERFLOW) { -+ process_q_overflow(j); -+ return; -+ } -+ - /* Is this a subdirectory we watch? */ - d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd)); - if (d) { -diff --git a/src/shared/path-util.c b/src/shared/path-util.c -index 1181ffb9d..4d6e5e772 100644 ---- a/src/shared/path-util.c -+++ b/src/shared/path-util.c -@@ -738,3 +738,17 @@ char *prefix_root(const char *root, const char *path) { - strcpy(p, path); - return n; - } -+ -+int inotify_add_watch_fd(int fd, int what, uint32_t mask) { -+ char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; -+ int r; -+ -+ /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */ -+ xsprintf(path, "/proc/self/fd/%i", what); -+ -+ r = inotify_add_watch(fd, path, mask); -+ if (r < 0) -+ return -errno; -+ -+ return r; -+} -diff --git a/src/shared/path-util.h b/src/shared/path-util.h -index 71bb740e9..e14702da8 100644 ---- a/src/shared/path-util.h -+++ b/src/shared/path-util.h -@@ -65,6 +65,8 @@ int fsck_exists(const char *fstype); - - char *prefix_root(const char *root, const char *path); - -+int inotify_add_watch_fd(int fd, int what, uint32_t mask); -+ - /* Similar to prefix_root(), but returns an alloca() buffer, or - * possibly a const pointer into the path parameter */ - #define prefix_roota(root, path) \ diff --git a/SOURCES/0515-nspawn-new-option-to-start-as-PID2.patch b/SOURCES/0515-nspawn-new-option-to-start-as-PID2.patch new file mode 100644 index 0000000..6164a39 --- /dev/null +++ b/SOURCES/0515-nspawn-new-option-to-start-as-PID2.patch @@ -0,0 +1,491 @@ +From 41e91ccdf9fa3097d7b90718cc83e743f4dc8d6b Mon Sep 17 00:00:00 2001 +From: Jan Rybar +Date: Thu, 17 Aug 2017 18:01:42 +0200 +Subject: [PATCH] nspawn: new option to start as PID2 + +Cherry-picked from: 7732f92 +Resolves: #1417387 +--- + Makefile.am | 2 + + man/systemd-nspawn.xml | 65 ++++++++++++-- + src/nspawn/nspawn-stub-pid1.c | 196 ++++++++++++++++++++++++++++++++++++++++++ + src/nspawn/nspawn-stub-pid1.h | 22 +++++ + src/nspawn/nspawn.c | 56 ++++++++++-- + 5 files changed, 328 insertions(+), 13 deletions(-) + create mode 100644 src/nspawn/nspawn-stub-pid1.c + create mode 100644 src/nspawn/nspawn-stub-pid1.h + +diff --git a/Makefile.am b/Makefile.am +index 7c58fd050..0e2f8d561 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2658,6 +2658,8 @@ systemd_cgtop_LDADD = \ + # ------------------------------------------------------------------------------ + systemd_nspawn_SOURCES = \ + src/nspawn/nspawn.c \ ++ src/nspawn/nspawn-stub-pid1.c \ ++ src/nspawn/nspawn-stub-pid1.h \ + src/core/mount-setup.c \ + src/core/mount-setup.h \ + src/core/loopback-setup.c \ +diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml +index cbd44d4ab..d0eddaacc 100644 +--- a/man/systemd-nspawn.xml ++++ b/man/systemd-nspawn.xml +@@ -241,16 +241,69 @@ + . + + ++ ++ ++ ++ ++ Invoke the shell or specified program as process ID (PID) 2 instead of PID 1 (init). By ++ default, if neither this option nor is used, the selected binary is run as process with ++ PID 1, a mode only suitable for programs that are aware of the special semantics that the process with PID 1 ++ has on UNIX. For example, it needs to reap all processes reparented to it, and should implement ++ sysvinit compatible signal handling (specifically: it needs to reboot on SIGINT, reexecute ++ on SIGTERM, reload configuration on SIGHUP, and so on). With a minimal stub init ++ process is run as PID 1 and the selected binary is executed as PID 2 (and hence does not need to implement any ++ special semantics). The stub init process will reap processes as necessary and react appropriately to ++ signals. It is recommended to use this mode to invoke arbitrary commands in containers, unless they have been ++ modified to run correctly as PID 1. Or in other words: this switch should be used for pretty much all commands, ++ except when the command refers to an init or shell implementation, as these are generally capable of running ++ correctly as PID 1). This option may not be combined with or ++ . ++ ++ ++ + + + + +- Automatically search for an init binary and +- invoke it instead of a shell or a user supplied program. If +- this option is used, arguments specified on the command line +- are used as arguments for the init binary. This option may not +- be combined with . +- ++ Automatically search for an init binary and invoke it as PID 1, instead of a shell or a user ++ supplied program. If this option is used, arguments specified on the command line are used as arguments for the ++ init binary. This option may not be combined with or ++ . ++ ++ The following table explains the different modes of invocation and relationship to ++ (see above): ++ ++ ++ Invocation Mode ++ ++ ++ ++ ++ ++ Switch ++ Explanation ++ ++ ++ ++ ++ Neither nor specified ++ The passed parameters are interpreted as command line, which is executed as PID 1 in the container. ++ ++ ++ ++ specified ++ The passed parameters are interpreted as command line, which are executed as PID 2 in the container. A stub init process is run as PID 1. ++ ++ ++ ++ specified ++ An init binary as automatically searched and run as PID 1 in the container. The passed parameters are used as invocation parameters for this process. ++ ++ ++ ++ ++
++
+
+ + +diff --git a/src/nspawn/nspawn-stub-pid1.c b/src/nspawn/nspawn-stub-pid1.c +new file mode 100644 +index 000000000..11c11560c +--- /dev/null ++++ b/src/nspawn/nspawn-stub-pid1.c +@@ -0,0 +1,196 @@ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2016 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 ++#include ++ ++#include "log.h" ++#include "nspawn-stub-pid1.h" ++#include "util.h" ++#include "time-util.h" ++#include "def.h" ++ ++static int reset_environ(const char *new_environment, size_t length) { ++ unsigned long start, end; ++ ++ start = (unsigned long) new_environment; ++ end = start + length; ++ ++ if (prctl(PR_SET_MM, PR_SET_MM_ENV_START, start, 0, 0) < 0) ++ return -errno; ++ ++ if (prctl(PR_SET_MM, PR_SET_MM_ENV_END, end, 0, 0) < 0) ++ return -errno; ++ ++ return 0; ++} ++ ++int stub_pid1(sd_id128_t uuid) { ++ enum { ++ STATE_RUNNING, ++ STATE_REBOOT, ++ STATE_POWEROFF, ++ } state = STATE_RUNNING; ++ ++ sigset_t fullmask, oldmask, waitmask; ++ usec_t quit_usec = USEC_INFINITY; ++ pid_t pid; ++ int r; ++ ++ /* The new environment we set up, on the stack. */ ++ char new_environment[] = ++ "container=systemd-nspawn\0" ++ "container_uuid=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; ++ ++ /* Implements a stub PID 1, that reaps all processes and processes a couple of standard signals. This is useful ++ * for allowing arbitrary processes run in a container, and still have all zombies reaped. */ ++ ++ assert_se(sigfillset(&fullmask) >= 0); ++ assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0); ++ ++ pid = fork(); ++ if (pid < 0) ++ return log_error_errno(errno, "Failed to fork child pid: %m"); ++ ++ if (pid == 0) { ++ /* Return in the child */ ++ assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) >= 0); ++ setsid(); ++ return 0; ++ } ++ ++ reset_all_signal_handlers(); ++ ++ log_close(); ++ close_all_fds(NULL, 0); ++ log_open(); ++ ++ /* Flush out /proc/self/environ, so that we don't leak the environment from the host into the container. Also, ++ * set $container= and $container_uuid= so that clients in the container that query it from /proc/1/environ ++ * find them set. */ ++ sd_id128_to_string(uuid, new_environment + sizeof(new_environment) - SD_ID128_STRING_MAX); ++ reset_environ(new_environment, sizeof(new_environment)); ++ ++ rename_process("STUBINIT"); ++ ++ assert_se(sigemptyset(&waitmask) >= 0); ++ ++ sigset_add_many(&waitmask, ++ SIGCHLD, /* posix: process died */ ++ SIGINT, /* sysv: ctrl-alt-del */ ++ SIGRTMIN+3, /* systemd: halt */ ++ SIGRTMIN+4, /* systemd: poweroff */ ++ SIGRTMIN+5, /* systemd: reboot */ ++ SIGRTMIN+6, /* systemd: kexec */ ++ SIGRTMIN+13, /* systemd: halt */ ++ SIGRTMIN+14, /* systemd: poweroff */ ++ SIGRTMIN+15, /* systemd: reboot */ ++ SIGRTMIN+16, /* systemd: kexec */ ++ -1); ++ ++ /* Note that we ignore SIGTERM (sysv's reexec), SIGHUP (reload), and all other signals here, since we don't ++ * support reexec/reloading in this stub process. */ ++ ++ for (;;) { ++ siginfo_t si; ++ usec_t current_usec; ++ ++ si.si_pid = 0; ++ r = waitid(P_ALL, 0, &si, WEXITED|WNOHANG); ++ if (r < 0) { ++ r = log_error_errno(errno, "Failed to reap children: %m"); ++ goto finish; ++ } ++ ++ current_usec = now(CLOCK_MONOTONIC); ++ ++ if (si.si_pid == pid || current_usec >= quit_usec) { ++ ++ /* The child we started ourselves died or we reached a timeout. */ ++ ++ if (state == STATE_REBOOT) { /* dispatch a queued reboot */ ++ (void) reboot(RB_AUTOBOOT); ++ r = log_error_errno(errno, "Failed to reboot: %m"); ++ goto finish; ++ ++ } else if (state == STATE_POWEROFF) ++ (void) reboot(RB_POWER_OFF); /* if this fails, fall back to normal exit. */ ++ ++ if (si.si_pid == pid && si.si_code == CLD_EXITED) ++ r = si.si_status; /* pass on exit code */ ++ else ++ r = 255; /* signal, coredump, timeout, … */ ++ ++ goto finish; ++ } ++ if (si.si_pid != 0) ++ /* We reaped something. Retry until there's nothing more to reap. */ ++ continue; ++ ++ if (quit_usec == USEC_INFINITY) ++ r = sigwaitinfo(&waitmask, &si); ++ else { ++ struct timespec ts; ++ r = sigtimedwait(&waitmask, &si, timespec_store(&ts, quit_usec - current_usec)); ++ } ++ if (r < 0) { ++ if (errno == EINTR) /* strace -p attach can result in EINTR, let's handle this nicely. */ ++ continue; ++ if (errno == EAGAIN) /* timeout reached */ ++ continue; ++ ++ r = log_error_errno(errno, "Failed to wait for signal: %m"); ++ goto finish; ++ } ++ ++ if (si.si_signo == SIGCHLD) ++ continue; /* Let's reap this */ ++ ++ if (state != STATE_RUNNING) ++ continue; ++ ++ /* Would love to use a switch() statement here, but SIGRTMIN is actually a function call, not a ++ * constant… */ ++ ++ if (si.si_signo == SIGRTMIN+3 || ++ si.si_signo == SIGRTMIN+4 || ++ si.si_signo == SIGRTMIN+13 || ++ si.si_signo == SIGRTMIN+14) ++ ++ state = STATE_POWEROFF; ++ ++ else if (si.si_signo == SIGINT || ++ si.si_signo == SIGRTMIN+5 || ++ si.si_signo == SIGRTMIN+6 || ++ si.si_signo == SIGRTMIN+15 || ++ si.si_signo == SIGRTMIN+16) ++ ++ state = STATE_REBOOT; ++ else ++ assert_not_reached("Got unexpected signal"); ++ ++ /* (void) kill_and_sigcont(pid, SIGTERM); */ ++ quit_usec = now(CLOCK_MONOTONIC) + DEFAULT_TIMEOUT_USEC; ++ } ++ ++finish: ++ _exit(r < 0 ? EXIT_FAILURE : r); ++} +diff --git a/src/nspawn/nspawn-stub-pid1.h b/src/nspawn/nspawn-stub-pid1.h +new file mode 100644 +index 000000000..be0f1af4c +--- /dev/null ++++ b/src/nspawn/nspawn-stub-pid1.h +@@ -0,0 +1,22 @@ ++#pragma once ++ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2016 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 . ++***/ ++ ++int stub_pid1(sd_id128_t uuid); +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index d0003d379..ea365b3f9 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -99,6 +99,7 @@ + #include "in-addr-util.h" + #include "fw-util.h" + #include "local-addresses.h" ++#include "nspawn-stub-pid1.h" + + #ifdef HAVE_SECCOMP + #include "seccomp-util.h" +@@ -129,6 +130,14 @@ typedef enum Volatile { + VOLATILE_STATE, + } Volatile; + ++typedef enum StartMode { ++ START_PID1, /* Run parameters as command line as process 1 */ ++ START_PID2, /* Use stub init process as PID 1, run parameters as command line as process 2 */ ++ START_BOOT, /* Search for init system, pass arguments as parameters */ ++ _START_MODE_MAX, ++ _START_MODE_INVALID = -1 ++} StartMode; ++ + static char *arg_directory = NULL; + static char *arg_template = NULL; + static char *arg_user = NULL; +@@ -139,7 +148,7 @@ static const char *arg_selinux_apifs_context = NULL; + static const char *arg_slice = NULL; + static bool arg_private_network = false; + static bool arg_read_only = false; +-static bool arg_boot = false; ++static StartMode arg_start_mode = START_PID1; + static bool arg_ephemeral = false; + static LinkJournal arg_link_journal = LINK_AUTO; + static bool arg_link_journal_try = false; +@@ -200,6 +209,7 @@ static void help(void) { + " -x --ephemeral Run container with snapshot of root directory, and\n" + " remove it after exit\n" + " -i --image=PATH File system device or disk image for the container\n" ++ " -a --as-pid2 Maintain a stub init as PID1, invoke binary as PID2\n" + " -b --boot Boot up full system (i.e. invoke init)\n" + " -u --user=USER Run the command under specified user or uid\n" + " -M --machine=NAME Set the machine name for the container\n" +@@ -304,6 +314,7 @@ static int parse_argv(int argc, char *argv[]) { + { "ephemeral", no_argument, NULL, 'x' }, + { "user", required_argument, NULL, 'u' }, + { "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK }, ++ { "as-pid2", no_argument, NULL, 'a' }, + { "boot", no_argument, NULL, 'b' }, + { "uuid", required_argument, NULL, ARG_UUID }, + { "read-only", no_argument, NULL, ARG_READ_ONLY }, +@@ -340,7 +351,7 @@ static int parse_argv(int argc, char *argv[]) { + assert(argc >= 0); + assert(argv); + +- while ((c = getopt_long(argc, argv, "+hD:u:bL:M:jS:Z:qi:xp:n", options, NULL)) >= 0) ++ while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:n", options, NULL)) >= 0) + + switch (c) { + +@@ -421,7 +432,21 @@ static int parse_argv(int argc, char *argv[]) { + break; + + case 'b': +- arg_boot = true; ++ if (arg_start_mode == START_PID2) { ++ log_error("--boot and --as-pid2 may not be combined."); ++ return -EINVAL; ++ } ++ ++ arg_start_mode = START_BOOT; ++ break; ++ ++ case 'a': ++ if (arg_start_mode == START_BOOT) { ++ log_error("--boot and --as-pid2 may not be combined."); ++ return -EINVAL; ++ } ++ ++ arg_start_mode = START_PID2; + break; + + case ARG_UUID: +@@ -741,7 +766,7 @@ static int parse_argv(int argc, char *argv[]) { + if (arg_share_system) + arg_register = false; + +- if (arg_boot && arg_share_system) { ++ if (arg_start_mode != START_PID1 && arg_share_system) { + log_error("--boot and --share-system may not be combined."); + return -EINVAL; + } +@@ -3586,6 +3611,10 @@ int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + ++ /* Make sure rename_process() in the stub init process can work */ ++ saved_argv = argv; ++ saved_argc = argc; ++ + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; +@@ -3694,7 +3723,7 @@ int main(int argc, char *argv[]) { + } + } + +- if (arg_boot) { ++ if (arg_start_mode == START_BOOT) { + if (path_is_os_tree(arg_directory) <= 0) { + log_error("Directory %s doesn't look like an OS root directory (os-release file is missing). Refusing.", arg_directory); + r = -EINVAL; +@@ -4109,7 +4138,19 @@ int main(int argc, char *argv[]) { + if (!barrier_place_and_sync(&barrier)) + _exit(EXIT_FAILURE); + +- if (arg_boot) { ++ if (arg_start_mode == START_PID2) { ++ r = stub_pid1(arg_uuid); ++ if (r < 0) ++ { ++ log_error_errno(r, "Failed to start as PID2: %m"); ++ _exit(EXIT_FAILURE); ++ } ++ } ++ ++ log_close(); ++ (void) fdset_close_others(fds); ++ ++ if (arg_start_mode == START_BOOT) { + char **a; + size_t l; + +@@ -4135,6 +4176,7 @@ int main(int argc, char *argv[]) { + execle("/bin/sh", "-sh", NULL, env_use); + } + ++ log_open(); + log_error_errno(errno, "execv() failed: %m"); + _exit(EXIT_FAILURE); + } +@@ -4210,7 +4252,7 @@ int main(int argc, char *argv[]) { + goto finish; + } + +- if (arg_boot) { ++ if (arg_start_mode == START_BOOT) { + /* Try to kill the init system on SIGINT or SIGTERM */ + sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, UINT32_TO_PTR(pid)); + sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, UINT32_TO_PTR(pid)); diff --git a/SOURCES/0515-sd-journal-make-sure-it-s-safe-to-call-sd_journal_pr.patch b/SOURCES/0515-sd-journal-make-sure-it-s-safe-to-call-sd_journal_pr.patch deleted file mode 100644 index c7ecc87..0000000 --- a/SOURCES/0515-sd-journal-make-sure-it-s-safe-to-call-sd_journal_pr.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 3822b85386edacc9aaf07231b057fa847cdbde08 Mon Sep 17 00:00:00 2001 -From: Lennart Poettering -Date: Fri, 9 Feb 2018 22:38:46 +0100 -Subject: [PATCH] sd-journal: make sure it's safe to call sd_journal_process() - before the first sd_journal_wait() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -In that case we have no inotify fd yet, and there's nothing to process -hence. Let's make the call a NOP. - -(Previously, without this change we'd end up trying to read off inotify -fd -1, which is quite a problem... 😢) - -(cherry picked from commit 10c4d6405f74258ea4fac5db4888c1bf49ad5399) - -Related: #1540538 ---- - src/journal/sd-journal.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c -index 9186f5188..e1cde6e1c 100644 ---- a/src/journal/sd-journal.c -+++ b/src/journal/sd-journal.c -@@ -2329,6 +2329,9 @@ _public_ int sd_journal_process(sd_journal *j) { - assert_return(j, -EINVAL); - assert_return(!journal_pid_changed(j), -ECHILD); - -+ if (j->inotify_fd < 0) /* We have no inotify fd yet? Then there's noting to process. */ -+ return 0; -+ - j->last_process_usec = now(CLOCK_MONOTONIC); - j->last_invalidate_counter = j->current_invalidate_counter; - diff --git a/SOURCES/0516-journal-implicitly-flush-to-var-on-recovery-4028.patch b/SOURCES/0516-journal-implicitly-flush-to-var-on-recovery-4028.patch new file mode 100644 index 0000000..6094a08 --- /dev/null +++ b/SOURCES/0516-journal-implicitly-flush-to-var-on-recovery-4028.patch @@ -0,0 +1,77 @@ +From 80f0fa4a77bfceab3bae7cf67f44b8f899b22427 Mon Sep 17 00:00:00 2001 +From: Vito Caputo +Date: Tue, 18 Jul 2017 18:00:37 +0200 +Subject: [PATCH] journal: implicitly flush to var on recovery (#4028) + +When the system journal becomes re-opened post-flush with the runtime +journal open, it implies we've recovered from something like an ENOSPC +situation where the system journal rotate had failed, leaving the system +journal closed, causing the runtime journal to be opened post-flush. + +For the duration of the unavailable system journal, we log to the +runtime journal. But when the system journal gets opened (space made +available, for example), we need to close the runtime journal before new +journal writes will go to the system journal. Calling +server_flush_to_var() after opening the system journal with a runtime +journal present, post-flush, achieves this while preserving the runtime +journal's contents in the system journal. + +The combination of the present flushed flag file and the runtime journal +being open is a state where we should be logging to the system journal, +so it's appropriate to resume doing so once we've successfully opened +the system journal. + +(cherry picked from commit 929eeb5498e8ae87e05ae683c6d3014d4b59056d) + +Related: #1364092 +--- + src/journal/journald-server.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 2b7ecd09a..3e9412d57 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -923,6 +923,7 @@ static int system_journal_open(Server *s, bool flush_requested) { + char *fn; + sd_id128_t machine; + char ids[33]; ++ bool flushed = false; + + r = sd_id128_get_machine(&machine); + if (r < 0) +@@ -933,7 +934,7 @@ static int system_journal_open(Server *s, bool flush_requested) { + if (!s->system_journal && + (s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) && + (flush_requested +- || access("/run/systemd/journal/flushed", F_OK) >= 0)) { ++ || (flushed = (access("/run/systemd/journal/flushed", F_OK) >= 0)))) { + + /* If in auto mode: first try to create the machine + * path, but not the prefix. +@@ -958,6 +959,16 @@ static int system_journal_open(Server *s, bool flush_requested) { + + r = 0; + } ++ ++ /* If the runtime journal is open, and we're post-flush, we're ++ * recovering from a failed system journal rotate (ENOSPC) ++ * for which the runtime journal was reopened. ++ * ++ * Perform an implicit flush to var, leaving the runtime ++ * journal closed, now that the system journal is back. ++ */ ++ if (s->runtime_journal && flushed) ++ (void) server_flush_to_var(s); + } + + if (!s->runtime_journal && +@@ -1230,7 +1241,7 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo * + + log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid); + +- server_flush_to_var(s); ++ (void) server_flush_to_var(s); + server_sync(s); + server_vacuum(s); + diff --git a/SOURCES/0516-sd-journal-when-picking-up-a-new-file-compare-inode-.patch b/SOURCES/0516-sd-journal-when-picking-up-a-new-file-compare-inode-.patch deleted file mode 100644 index 82bb1bf..0000000 --- a/SOURCES/0516-sd-journal-when-picking-up-a-new-file-compare-inode-.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 6fc12b327982851378333d24fc902c3540dadc0e Mon Sep 17 00:00:00 2001 -From: Michal Sekletar -Date: Tue, 20 Feb 2018 14:16:15 +0100 -Subject: [PATCH] sd-journal: when picking up a new file, compare inode/device - info with previous open file by same name - -Let's make sure we aren't confused if a journal file is replaced by a -different one (for example due to rotation) if we are in a q overflow: -let's compare the inode/device information, and if it changed replace -any open file object as needed. - -Fixes: #8198 - -(cherry-picked from commit 32cb1983ad6f7084ff86e259ff079742a8139719) - -[msekleta: this is very slimmed down version of the above commit because -a lot of code from is not applicable to RHEL-7 version] - -Related: #1540538 ---- - src/journal/sd-journal.c | 35 +++++++++++++++++++++++++++++------ - 1 file changed, 29 insertions(+), 6 deletions(-) - -diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c -index e1cde6e1c..004fe646d 100644 ---- a/src/journal/sd-journal.c -+++ b/src/journal/sd-journal.c -@@ -1224,20 +1224,43 @@ static bool file_type_wanted(int flags, const char *filename) { - - static int add_any_file(sd_journal *j, const char *path) { - JournalFile *f = NULL; -+ struct stat st; - int r, k; - - assert(j); - assert(path); - -- if (path) { -- f = ordered_hashmap_get(j->files, path); -- if (f) { -- /* Mark this file as seen in this generation. This is used to GC old files in -- * process_q_overflow() to detect journal files that are still and discern them from those who -- * are gone. */ -+ if (stat(path, &st) < 0) { -+ r = log_debug_errno(errno, "Failed to stat file '%s': %m", path); -+ return -errno; -+ } -+ if (S_ISDIR(st.st_mode)) { -+ log_debug("Uh, file '%s' is a directory? Refusing.", path); -+ return -EISDIR; -+ } -+ if (!S_ISREG(st.st_mode)) { -+ log_debug("Uh, file '%s' is not a regular file? Refusing.", path); -+ return -EBADFD; -+ } -+ -+ f = ordered_hashmap_get(j->files, path); -+ if (f) { -+ -+ if (f->last_stat.st_dev == st.st_dev && -+ f->last_stat.st_ino == st.st_ino) { -+ -+ /* We already track this file, under the same path and with the same device/inode numbers, it's hence -+ * really the same. Mark this file as seen in this generation. This is used to GC old files in -+ * process_q_overflow() to detect journal files that are still and discern them from those who are -+ * gone. */ - f->last_seen_generation = j->generation; - return 0; - } -+ -+ /* So we tracked a file under this name, but it has a different inode/device. In that case, it got -+ * replaced (probably due to rotation?), let's drop it hence from our list. */ -+ remove_file_real(j, f); -+ f = NULL; - } - - if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { diff --git a/SOURCES/0517-journal-add-use-flushed_flag_is_set-helper-4041.patch b/SOURCES/0517-journal-add-use-flushed_flag_is_set-helper-4041.patch new file mode 100644 index 0000000..85b7a59 --- /dev/null +++ b/SOURCES/0517-journal-add-use-flushed_flag_is_set-helper-4041.patch @@ -0,0 +1,38 @@ +From 0adc312bbf5ea8ea654a5a4740f78f37eda2e9d3 Mon Sep 17 00:00:00 2001 +From: Vito Caputo +Date: Thu, 17 Aug 2017 09:45:38 +0200 +Subject: [PATCH] journal: add/use flushed_flag_is_set() helper (#4041) + +Minor cleanup suggested by Lennart. + +(cherry-picked from commit 6431c7e216ceb9f3cfe073c94a47ac413b892e55) + +Related: #1364092 +--- + src/journal/journald-server.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 3e9412d57..96ffda4ec 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -917,6 +917,9 @@ finish: + dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid); + } + ++static bool flushed_flag_is_set(void) { ++ return (access("/run/systemd/journal/flushed", F_OK) >= 0); ++} + + static int system_journal_open(Server *s, bool flush_requested) { + int r; +@@ -933,8 +936,7 @@ static int system_journal_open(Server *s, bool flush_requested) { + + if (!s->system_journal && + (s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) && +- (flush_requested +- || (flushed = (access("/run/systemd/journal/flushed", F_OK) >= 0)))) { ++ (flush_requested || (flushed = flushed_flag_is_set()))) { + + /* If in auto mode: first try to create the machine + * path, but not the prefix. diff --git a/SOURCES/0517-journalctl-Periodically-call-sd_journal_process-in-j.patch b/SOURCES/0517-journalctl-Periodically-call-sd_journal_process-in-j.patch deleted file mode 100644 index 8bced24..0000000 --- a/SOURCES/0517-journalctl-Periodically-call-sd_journal_process-in-j.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 6241ea7b14a47a820e5d692a44056fa7181242cf Mon Sep 17 00:00:00 2001 -From: Peter Portante -Date: Sun, 28 Jan 2018 16:48:04 -0500 -Subject: [PATCH] journalctl: Periodically call sd_journal_process in - journalctl - -If `journalctl` take a long time to process messages, and during that -time journal file rotation occurs, a `journalctl` client will keep -those rotated files open until it calls `sd_journal_process()`, which -typically happens as a result of calling `sd_journal_wait()` below in -the "following" case. By periodically calling `sd_journal_process()` -during the processing loop we shrink the window of time a client -instance has open file descriptors for rotated (deleted) journal -files. - -(Lennart: slightly reworked version, that dropped some of the commenting -which was solved otherwise) - -(cherry picked from commit ec316d199a13d8db3f6550d60e369893de2fb417) - -Related: #1540538 ---- - src/journal/journalctl.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c -index 0be70764e..1e6d0761c 100644 ---- a/src/journal/journalctl.c -+++ b/src/journal/journalctl.c -@@ -67,6 +67,8 @@ - - #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) - -+#define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */ -+ - enum { - /* Special values for arg_lines */ - ARG_LINES_DEFAULT = -2, -@@ -2294,6 +2296,20 @@ int main(int argc, char *argv[]) { - goto finish; - - n_shown++; -+ -+ /* If journalctl take a long time to process messages, and during that time journal file -+ * rotation occurs, a journalctl client will keep those rotated files open until it calls -+ * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below -+ * in the "following" case. By periodically calling sd_journal_process() during the processing -+ * loop we shrink the window of time a client instance has open file descriptors for rotated -+ * (deleted) journal files. */ -+ if ((n_shown % PROCESS_INOTIFY_INTERVAL) == 0) { -+ r = sd_journal_process(j); -+ if (r < 0) { -+ log_error_errno(r, "Failed to process inotify events: %m"); -+ goto finish; -+ } -+ } - } - - if (!arg_follow) { diff --git a/SOURCES/0518-journald-don-t-flush-to-var-log-journal-before-we-ge.patch b/SOURCES/0518-journald-don-t-flush-to-var-log-journal-before-we-ge.patch new file mode 100644 index 0000000..d355027 --- /dev/null +++ b/SOURCES/0518-journald-don-t-flush-to-var-log-journal-before-we-ge.patch @@ -0,0 +1,142 @@ +From 6032a92b8fb27a7c65a1853e62a142fd9a062b73 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 17 Aug 2017 10:21:23 +0200 +Subject: [PATCH] journald: don't flush to /var/log/journal before we get asked + to + +This changes journald to not write to /var/log/journal until it received +SIGUSR1 for the first time, thus having been requested to flush the runtime +journal to disk. + +This makes the journal work nicer with systems which have the root file system +writable early, but still need to rearrange /var before journald should start +writing and creating files to it, for example because ACLs need to be applied +first, or because /var is to be mounted from another file system, NFS or tmpfs +(as is the case for systemd.volatile=state). + +Before this change we required setupts with /var split out to mount the root +disk read-only early on, and ship an /etc/fstab that remounted it writable only +after having placed /var at the right place. But even that was racy for various +preparations as journald might end up accessing the file system before it was +entirely set up, as soon as it was writable. + +With this change we make scheduling when to start writing to /var/log/journal +explicit. This means persistent mode now requires +systemd-journal-flush.service in the mix to work, as otherwise journald would +never write to the directory. + +See: #1397 + +(cherry-picked from commit f78273c8dacf678cc8fd7387f678e6344a99405c) + +Resolves: #1364092 +--- + src/journal/journald-server.c | 21 +++++++++++---------- + src/journal/journald-server.h | 2 +- + src/journal/journald.c | 2 +- + 3 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 96ffda4ec..07426b41e 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -918,7 +918,7 @@ finish: + } + + static bool flushed_flag_is_set(void) { +- return (access("/run/systemd/journal/flushed", F_OK) >= 0); ++ return access("/run/systemd/journal/flushed", F_OK) >= 0; + } + + static int system_journal_open(Server *s, bool flush_requested) { +@@ -926,7 +926,6 @@ static int system_journal_open(Server *s, bool flush_requested) { + char *fn; + sd_id128_t machine; + char ids[33]; +- bool flushed = false; + + r = sd_id128_get_machine(&machine); + if (r < 0) +@@ -935,8 +934,8 @@ static int system_journal_open(Server *s, bool flush_requested) { + sd_id128_to_string(machine, ids); + + if (!s->system_journal && +- (s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) && +- (flush_requested || (flushed = flushed_flag_is_set()))) { ++ IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) && ++ (flush_requested || flushed_flag_is_set())) { + + /* If in auto mode: first try to create the machine + * path, but not the prefix. +@@ -969,8 +968,8 @@ static int system_journal_open(Server *s, bool flush_requested) { + * Perform an implicit flush to var, leaving the runtime + * journal closed, now that the system journal is back. + */ +- if (s->runtime_journal && flushed) +- (void) server_flush_to_var(s); ++ if (!flush_requested) ++ (void) server_flush_to_var(s, true); + } + + if (!s->runtime_journal && +@@ -1021,7 +1020,7 @@ static int system_journal_open(Server *s, bool flush_requested) { + return r; + } + +-int server_flush_to_var(Server *s) { ++int server_flush_to_var(Server *s, bool require_flag_file) { + sd_id128_t machine; + sd_journal *j = NULL; + char ts[FORMAT_TIMESPAN_MAX]; +@@ -1031,13 +1030,15 @@ int server_flush_to_var(Server *s) { + + assert(s); + +- if (s->storage != STORAGE_AUTO && +- s->storage != STORAGE_PERSISTENT) ++ if (!IN_SET(s->storage, STORAGE_AUTO, STORAGE_PERSISTENT)) + return 0; + + if (!s->runtime_journal) + return 0; + ++ if (require_flag_file && !flushed_flag_is_set()) ++ return 0; ++ + system_journal_open(s, true); + + if (!s->system_journal) +@@ -1243,7 +1244,7 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo * + + log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid); + +- (void) server_flush_to_var(s); ++ (void) server_flush_to_var(s, false); + server_sync(s); + server_vacuum(s); + +diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h +index b1263a758..7a456c2d5 100644 +--- a/src/journal/journald-server.h ++++ b/src/journal/journald-server.h +@@ -173,6 +173,6 @@ void server_sync(Server *s); + void server_vacuum(Server *s); + void server_rotate(Server *s); + int server_schedule_sync(Server *s, int priority); +-int server_flush_to_var(Server *s); ++int server_flush_to_var(Server *s, bool require_flag_file); + void server_maybe_append_tags(Server *s); + int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata); +diff --git a/src/journal/journald.c b/src/journal/journald.c +index 80f4634f6..15bbcbe3d 100644 +--- a/src/journal/journald.c ++++ b/src/journal/journald.c +@@ -58,7 +58,7 @@ int main(int argc, char *argv[]) { + goto finish; + + server_vacuum(&server); +- server_flush_to_var(&server); ++ server_flush_to_var(&server, true); + server_flush_dev_kmsg(&server); + + log_debug("systemd-journald running as pid "PID_FMT, getpid()); diff --git a/SOURCES/0519-path-util-make-use-of-mnt_id-field-exported-in-proc-.patch b/SOURCES/0519-path-util-make-use-of-mnt_id-field-exported-in-proc-.patch new file mode 100644 index 0000000..82925c7 --- /dev/null +++ b/SOURCES/0519-path-util-make-use-of-mnt_id-field-exported-in-proc-.patch @@ -0,0 +1,560 @@ +From f63b66b6347a8d8e5e6930a939d1997bfd8e2e7c Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 28 Jul 2017 15:31:50 +0200 +Subject: [PATCH] path-util: make use of "mnt_id" field exported in + /proc/self/fdinfo/ + +This commit is not a backport of a specific commit. It includes parts of +several upstream commits (3f72b427b44f39a1aec6806dad6f6b57103ae9ed, +5d409034017e9f9f8c4392157d95511fc2e05d87 and others). + +The main goal was to bring path_is_mount_point() up to date, which meant +introducing fd_fdinfo_mnt_id() and fd_is_mount_point(). These were +needed mainly because we need to determine mount points based on +/proc/self/fdinfo/ in containers. Also, there are more places in the +code where checks for mount points are performed, which would benefit from +this fix as well. Additionally, corresponding tests has been added. + +Resolves: #1472439 +--- + src/core/automount.c | 2 +- + src/core/machine-id-setup.c | 2 +- + src/core/mount-setup.c | 2 +- + src/efi-boot-generator/efi-boot-generator.c | 2 +- + src/gpt-auto-generator/gpt-auto-generator.c | 2 +- + src/login/logind-user.c | 2 +- + src/nspawn/nspawn.c | 10 +- + src/shared/cgroup-util.c | 2 +- + src/shared/condition.c | 2 +- + src/shared/path-util.c | 209 ++++++++++++++++++++++------ + src/shared/path-util.h | 3 +- + src/test/test-path-util.c | 66 ++++++++- + 12 files changed, 242 insertions(+), 62 deletions(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index 4e066613d..eedd9b824 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -749,7 +749,7 @@ static int automount_start(Unit *u) { + assert(a); + assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED); + +- if (path_is_mount_point(a->where, false)) { ++ if (path_is_mount_point(a->where, 0)) { + log_unit_error(u->id, + "Path %s is already a mount point, refusing start for %s", + a->where, u->id); +diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c +index d00a53246..1121d373f 100644 +--- a/src/core/machine-id-setup.c ++++ b/src/core/machine-id-setup.c +@@ -203,7 +203,7 @@ int machine_id_commit(const char *root) { + etc_machine_id = path_kill_slashes(x); + } + +- r = path_is_mount_point(etc_machine_id, false); ++ r = path_is_mount_point(etc_machine_id, 0); + if (r < 0) + return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", etc_machine_id); + if (r == 0) { +diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c +index 521545e5c..2b8fbab1a 100644 +--- a/src/core/mount-setup.c ++++ b/src/core/mount-setup.c +@@ -160,7 +160,7 @@ static int mount_one(const MountPoint *p, bool relabel) { + if (relabel) + label_fix(p->where, true, true); + +- r = path_is_mount_point(p->where, true); ++ r = path_is_mount_point(p->where, AT_SYMLINK_FOLLOW); + if (r < 0) + return r; + +diff --git a/src/efi-boot-generator/efi-boot-generator.c b/src/efi-boot-generator/efi-boot-generator.c +index b3ff3a8b7..5492b1994 100644 +--- a/src/efi-boot-generator/efi-boot-generator.c ++++ b/src/efi-boot-generator/efi-boot-generator.c +@@ -69,7 +69,7 @@ int main(int argc, char *argv[]) { + return EXIT_SUCCESS; + } + +- if (path_is_mount_point("/boot", true) <= 0 && ++ if (path_is_mount_point("/boot", AT_SYMLINK_FOLLOW) <= 0 && + dir_is_empty("/boot") <= 0) { + log_debug("/boot already populated, exiting."); + return EXIT_SUCCESS; +diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c +index 00a2141a5..d7b047118 100644 +--- a/src/gpt-auto-generator/gpt-auto-generator.c ++++ b/src/gpt-auto-generator/gpt-auto-generator.c +@@ -299,7 +299,7 @@ static int probe_and_add_mount( + assert(where); + assert(description); + +- if (path_is_mount_point(where, true) <= 0 && ++ if (path_is_mount_point(where, AT_SYMLINK_FOLLOW) <= 0 && + dir_is_empty(where) <= 0) { + log_debug("%s already populated, ignoring.", where); + return 0; +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 4298704ce..912c50ebd 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -320,7 +320,7 @@ static int user_mkdir_runtime_path(User *u) { + } else + p = u->runtime_path; + +- if (path_is_mount_point(p, false) <= 0) { ++ if (path_is_mount_point(p, 0) <= 0) { + _cleanup_free_ char *t = NULL; + + (void) mkdir(p, 0700); +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index ea365b3f9..a90a3a5d7 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -863,7 +863,7 @@ static int mount_all(const char *dest) { + if (!where) + return log_oom(); + +- t = path_is_mount_point(where, true); ++ t = path_is_mount_point(where, AT_SYMLINK_FOLLOW); + if (t < 0) { + log_error_errno(t, "Failed to detect whether %s is a mount point: %m", where); + +@@ -989,7 +989,7 @@ static int mount_cgroup_hierarchy(const char *dest, const char *controller, cons + + to = strjoina(dest, "/sys/fs/cgroup/", hierarchy); + +- r = path_is_mount_point(to, false); ++ r = path_is_mount_point(to, 0); + if (r < 0) + return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to); + if (r > 0) +@@ -1787,7 +1787,7 @@ static int setup_journal(const char *directory) { + if (!p || !q) + return log_oom(); + +- if (path_is_mount_point(p, false) > 0) { ++ if (path_is_mount_point(p, 0) > 0) { + if (arg_link_journal != LINK_AUTO) { + log_error("%s: already a mount point, refusing to use for journal", p); + return -EEXIST; +@@ -1796,7 +1796,7 @@ static int setup_journal(const char *directory) { + return 0; + } + +- if (path_is_mount_point(q, false) > 0) { ++ if (path_is_mount_point(q, 0) > 0) { + if (arg_link_journal != LINK_AUTO) { + log_error("%s: already a mount point, refusing to use for journal", q); + return -EEXIST; +@@ -3665,7 +3665,7 @@ int main(int argc, char *argv[]) { + * the specified is not a mount point we + * create the new snapshot in the parent + * directory, just next to it. */ +- r = path_is_mount_point(arg_directory, false); ++ r = path_is_mount_point(arg_directory, 0); + if (r < 0) { + log_error_errno(r, "Failed to determine whether directory %s is mount point: %m", arg_directory); + goto finish; +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index c5d9e4bb5..cf085cb5f 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -488,7 +488,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch + if (_unlikely_(!good)) { + int r; + +- r = path_is_mount_point("/sys/fs/cgroup", false); ++ r = path_is_mount_point("/sys/fs/cgroup", 0); + if (r <= 0) + return r < 0 ? r : -ENOENT; + +diff --git a/src/shared/condition.c b/src/shared/condition.c +index 796cc520d..0d2cd2bc3 100644 +--- a/src/shared/condition.c ++++ b/src/shared/condition.c +@@ -350,7 +350,7 @@ static int condition_test_path_is_mount_point(Condition *c) { + assert(c->parameter); + assert(c->type == CONDITION_PATH_IS_MOUNT_POINT); + +- return path_is_mount_point(c->parameter, true) > 0; ++ return path_is_mount_point(c->parameter, AT_SYMLINK_FOLLOW) > 0; + } + + static int condition_test_path_is_read_write(Condition *c) { +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index 1181ffb9d..0f252ec26 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -36,6 +36,7 @@ + #include "strv.h" + #include "path-util.h" + #include "missing.h" ++#include "fileio.h" + + bool path_is_absolute(const char *p) { + return p[0] == '/'; +@@ -473,87 +474,203 @@ char* path_join(const char *root, const char *path, const char *rest) { + NULL); + } + +-int path_is_mount_point(const char *t, bool allow_symlink) { ++static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { ++ char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; ++ _cleanup_free_ char *fdinfo = NULL; ++ _cleanup_close_ int subfd = -1; ++ char *p; ++ int r; ++ ++ if ((flags & AT_EMPTY_PATH) && isempty(filename)) ++ xsprintf(path, "/proc/self/fdinfo/%i", fd); ++ else { ++ subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); ++ if (subfd < 0) ++ return -errno; ++ ++ xsprintf(path, "/proc/self/fdinfo/%i", subfd); ++ } ++ ++ r = read_full_file(path, &fdinfo, NULL); ++ if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ ++ return -EOPNOTSUPP; ++ if (r < 0) ++ return -errno; ++ ++ p = startswith(fdinfo, "mnt_id:"); ++ if (!p) { ++ p = strstr(fdinfo, "\nmnt_id:"); ++ if (!p) /* The mnt_id field is a relatively new addition */ ++ return -EOPNOTSUPP; ++ ++ p += 8; ++ } + +- union file_handle_union h = FILE_HANDLE_INIT; ++ p += strspn(p, WHITESPACE); ++ p[strcspn(p, WHITESPACE)] = 0; ++ ++ return safe_atoi(p, mnt_id); ++} ++ ++int fd_is_mount_point(int fd, const char *filename, int flags) { ++ union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; + int mount_id = -1, mount_id_parent = -1; +- _cleanup_free_ char *parent = NULL; ++ bool nosupp = false, check_st_dev = true; + struct stat a, b; + int r; +- bool nosupp = false; + +- /* We are not actually interested in the file handles, but +- * name_to_handle_at() also passes us the mount ID, hence use +- * it but throw the handle away */ ++ assert(fd >= 0); ++ assert(filename); + +- if (path_equal(t, "/")) +- return 1; +- +- r = name_to_handle_at(AT_FDCWD, t, &h.handle, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0); ++ /* First we will try the name_to_handle_at() syscall, which ++ * tells us the mount id and an opaque file "handle". It is ++ * not supported everywhere though (kernel compile-time ++ * option, not all file systems are hooked up). If it works ++ * the mount id is usually good enough to tell us whether ++ * something is a mount point. ++ * ++ * If that didn't work we will try to read the mount id from ++ * /proc/self/fdinfo/. This is almost as good as ++ * name_to_handle_at(), however, does not return the ++ * opaque file handle. The opaque file handle is pretty useful ++ * to detect the root directory, which we should always ++ * consider a mount point. Hence we use this only as ++ * fallback. Exporting the mnt_id in fdinfo is a pretty recent ++ * kernel addition. ++ * ++ * As last fallback we do traditional fstat() based st_dev ++ * comparisons. This is how things were traditionally done, ++ * but unionfs breaks breaks this since it exposes file ++ * systems with a variety of st_dev reported. Also, btrfs ++ * subvolumes have different st_dev, even though they aren't ++ * real mounts of their own. */ ++ ++ r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); + if (r < 0) { + if (errno == ENOSYS) + /* This kernel does not support name_to_handle_at() +- * fall back to the traditional stat() logic. */ +- goto fallback; ++ * fall back to simpler logic. */ ++ goto fallback_fdinfo; + else if (errno == EOPNOTSUPP) + /* This kernel or file system does not support +- * name_to_handle_at(), hence fallback to the ++ * name_to_handle_at(), hence let's see if the ++ * upper fs supports it (in which case it is a ++ * mount point), otherwise fallback to the + * traditional stat() logic */ + nosupp = true; +- else if (errno == ENOENT) +- return 0; + else + return -errno; + } + +- r = path_get_parent(t, &parent); +- if (r < 0) +- return r; +- +- h.handle.handle_bytes = MAX_HANDLE_SZ; +- r = name_to_handle_at(AT_FDCWD, parent, &h.handle, &mount_id_parent, AT_SYMLINK_FOLLOW); +- if (r < 0) +- if (errno == EOPNOTSUPP) ++ r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); ++ if (r < 0) { ++ if (errno == EOPNOTSUPP) { + if (nosupp) + /* Neither parent nor child do name_to_handle_at()? + We have no choice but to fall back. */ +- goto fallback; ++ goto fallback_fdinfo; + else +- /* The parent can't do name_to_handle_at() but +- * the directory we are interested in can? +- * Or the other way around? ++ /* The parent can't do name_to_handle_at() but the ++ * directory we are interested in can? + * If so, it must be a mount point. */ + return 1; +- else ++ } else + return -errno; +- else +- return mount_id != mount_id_parent; ++ } + +-fallback: +- if (allow_symlink) +- r = stat(t, &a); +- else +- r = lstat(t, &a); ++ /* The parent can do name_to_handle_at() but the ++ * directory we are interested in can't? If so, it ++ * must be a mount point. */ ++ if (nosupp) ++ return 1; + +- if (r < 0) { +- if (errno == ENOENT) +- return 0; ++ /* If the file handle for the directory we are ++ * interested in and its parent are identical, we ++ * assume this is the root directory, which is a mount ++ * point. */ + +- return -errno; +- } ++ if (h.handle.handle_bytes == h_parent.handle.handle_bytes && ++ h.handle.handle_type == h_parent.handle.handle_type && ++ memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) ++ return 1; + +- free(parent); +- parent = NULL; ++ return mount_id != mount_id_parent; + +- r = path_get_parent(t, &parent); ++fallback_fdinfo: ++ r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); ++ if (r == -EOPNOTSUPP) ++ goto fallback_fstat; + if (r < 0) + return r; + +- r = stat(parent, &b); ++ r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); + if (r < 0) ++ return r; ++ ++ if (mount_id != mount_id_parent) ++ return 1; ++ ++ /* Hmm, so, the mount ids are the same. This leaves one ++ * special case though for the root file system. For that, ++ * let's see if the parent directory has the same inode as we ++ * are interested in. Hence, let's also do fstat() checks now, ++ * too, but avoid the st_dev comparisons, since they aren't ++ * that useful on unionfs mounts. */ ++ check_st_dev = false; ++ ++fallback_fstat: ++ /* yay for fstatat() taking a different set of flags than the other ++ * _at() above */ ++ if (flags & AT_SYMLINK_FOLLOW) ++ flags &= ~AT_SYMLINK_FOLLOW; ++ else ++ flags |= AT_SYMLINK_NOFOLLOW; ++ if (fstatat(fd, filename, &a, flags) < 0) ++ return -errno; ++ ++ if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) ++ return -errno; ++ ++ /* A directory with same device and inode as its parent? Must ++ * be the root directory */ ++ if (a.st_dev == b.st_dev && ++ a.st_ino == b.st_ino) ++ return 1; ++ ++ return check_st_dev && (a.st_dev != b.st_dev); ++} ++ ++/* flags can be AT_SYMLINK_FOLLOW or 0 */ ++int path_is_mount_point(const char *t, int flags) { ++ _cleanup_close_ int fd = -1; ++ _cleanup_free_ char *canonical = NULL, *parent = NULL; ++ ++ assert(t); ++ ++ if (path_equal(t, "/")) ++ return 1; ++ ++ /* we need to resolve symlinks manually, we can't just rely on ++ * fd_is_mount_point() to do that for us; if we have a structure like ++ * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we ++ * look at needs to be /usr, not /. */ ++ if (flags & AT_SYMLINK_FOLLOW) { ++ canonical = canonicalize_file_name(t); ++ if (!canonical) ++ return -errno; ++ ++ t = canonical; ++ } ++ ++ parent = dirname_malloc(t); ++ if (!parent) ++ return -ENOMEM; ++ ++ fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); ++ if (fd < 0) + return -errno; + +- return a.st_dev != b.st_dev; ++ return fd_is_mount_point(fd, basename(t), flags); + } + + int path_is_read_only_fs(const char *path) { +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index 71bb740e9..e16484087 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -53,7 +53,8 @@ char** path_strv_make_absolute_cwd(char **l); + char** path_strv_resolve(char **l, const char *prefix); + char** path_strv_resolve_uniq(char **l, const char *prefix); + +-int path_is_mount_point(const char *path, bool allow_symlink); ++int fd_is_mount_point(int fd, const char *filename, int flags); ++int path_is_mount_point(const char *path, int flags); + int path_is_read_only_fs(const char *path); + int path_is_os_tree(const char *path); + +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index 6396fcb39..8870f178a 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -21,6 +21,7 @@ + + #include + #include ++#include + + #include "path-util.h" + #include "util.h" +@@ -85,8 +86,8 @@ static void test_path(void) { + test_parent("/aa///file...", "/aa///"); + test_parent("file.../", NULL); + +- assert_se(path_is_mount_point("/", true)); +- assert_se(path_is_mount_point("/", false)); ++ assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW)); ++ assert_se(path_is_mount_point("/", 0)); + + { + char p1[] = "aaa/bbb////ccc"; +@@ -99,6 +100,66 @@ static void test_path(void) { + } + } + ++static void test_path_is_mount_point(void) { ++ int fd, rt, rf, rlt, rlf; ++ char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX"; ++ _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL; ++ ++ assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW) > 0); ++ assert_se(path_is_mount_point("/", 0) > 0); ++ ++ assert_se(path_is_mount_point("/proc", AT_SYMLINK_FOLLOW) > 0); ++ assert_se(path_is_mount_point("/proc", 0) > 0); ++ ++ assert_se(path_is_mount_point("/proc/1", AT_SYMLINK_FOLLOW) == 0); ++ assert_se(path_is_mount_point("/proc/1", 0) == 0); ++ ++ assert_se(path_is_mount_point("/sys", AT_SYMLINK_FOLLOW) > 0); ++ assert_se(path_is_mount_point("/sys", 0) > 0); ++ ++ /* file mountpoints */ ++ assert_se(mkdtemp(tmp_dir) != NULL); ++ file1 = path_join(NULL, tmp_dir, "file1"); ++ assert_se(file1); ++ file2 = path_join(NULL, tmp_dir, "file2"); ++ assert_se(file2); ++ fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); ++ assert_se(fd > 0); ++ close(fd); ++ fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); ++ assert_se(fd > 0); ++ close(fd); ++ link1 = path_join(NULL, tmp_dir, "link1"); ++ assert_se(link1); ++ assert_se(symlink("file1", link1) == 0); ++ link2 = path_join(NULL, tmp_dir, "link2"); ++ assert_se(link1); ++ assert_se(symlink("file2", link2) == 0); ++ ++ assert_se(path_is_mount_point(file1, AT_SYMLINK_FOLLOW) == 0); ++ assert_se(path_is_mount_point(file1, 0) == 0); ++ assert_se(path_is_mount_point(link1, AT_SYMLINK_FOLLOW) == 0); ++ assert_se(path_is_mount_point(link1, 0) == 0); ++ ++ /* this test will only work as root */ ++ if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) { ++ rf = path_is_mount_point(file2, 0); ++ rt = path_is_mount_point(file2, AT_SYMLINK_FOLLOW); ++ rlf = path_is_mount_point(link2, 0); ++ rlt = path_is_mount_point(link2, AT_SYMLINK_FOLLOW); ++ ++ assert_se(umount(file2) == 0); ++ ++ assert_se(rf == 1); ++ assert_se(rt == 1); ++ assert_se(rlf == 0); ++ assert_se(rlt == 1); ++ } else ++ printf("Skipping bind mount file test: %m\n"); ++ ++ assert_se(rm_rf(tmp_dir, false, true, false) == 0); ++} ++ + static void test_find_binary(const char *self, bool local) { + char *p; + +@@ -288,6 +349,7 @@ int main(int argc, char **argv) { + test_make_relative(); + test_strv_resolve(); + test_path_startswith(); ++ test_path_is_mount_point(); + + return 0; + } diff --git a/SOURCES/0520-Revert-Revert-journald-allow-restarting-journald-wit.patch b/SOURCES/0520-Revert-Revert-journald-allow-restarting-journald-wit.patch new file mode 100644 index 0000000..3b12cdb --- /dev/null +++ b/SOURCES/0520-Revert-Revert-journald-allow-restarting-journald-wit.patch @@ -0,0 +1,546 @@ +From e0a3cd2cb02c465c13dcc4e2c092c9e14883ad59 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Wed, 3 Feb 2016 10:37:48 +0100 +Subject: [PATCH] Revert "Revert "journald: allow restarting journald without + losing stream connections"" + +This reverts commit 91cb89c1b79ef3c475d91319edb0c052cb9f2724. + +Resolves: #1359939 +--- + src/journal/journald-server.c | 26 ++- + src/journal/journald-stream.c | 371 ++++++++++++++++++++++++++++++++++++------ + src/journal/journald-stream.h | 3 +- + 3 files changed, 340 insertions(+), 60 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 07426b41e..c1358e1e9 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1477,6 +1477,7 @@ static int server_open_hostname(Server *s) { + } + + int server_init(Server *s) { ++ _cleanup_fdset_free_ FDSet *fds = NULL; + int n, r, fd; + + assert(s); +@@ -1573,26 +1574,33 @@ int server_init(Server *s) { + s->audit_fd = fd; + + } else { +- log_warning("Unknown socket passed as file descriptor %d, ignoring.", fd); + +- /* Let's close the fd, better be safe than +- sorry. The fd might reference some resource +- that we really want to release if we don't +- make use of it. */ ++ if (!fds) { ++ fds = fdset_new(); ++ if (!fds) ++ return log_oom(); ++ } + +- safe_close(fd); ++ r = fdset_put(fds, fd); ++ if (r < 0) ++ return log_oom(); + } + } + +- r = server_open_syslog_socket(s); ++ r = server_open_stdout_socket(s, fds); + if (r < 0) + return r; + +- r = server_open_native_socket(s); ++ if (fdset_size(fds) > 0) { ++ log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds)); ++ fds = fdset_free(fds); ++ } ++ ++ r = server_open_syslog_socket(s); + if (r < 0) + return r; + +- r = server_open_stdout_socket(s); ++ r = server_open_native_socket(s); + if (r < 0) + return r; + +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index b8607144b..15c9110c0 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -28,8 +28,11 @@ + #endif + + #include "sd-event.h" ++#include "sd-daemon.h" + #include "socket-util.h" + #include "selinux-util.h" ++#include "mkdir.h" ++#include "fileio.h" + #include "journald-server.h" + #include "journald-stream.h" + #include "journald-syslog.h" +@@ -66,14 +69,148 @@ struct StdoutStream { + bool forward_to_kmsg:1; + bool forward_to_console:1; + ++ bool fdstore:1; ++ + char buffer[LINE_MAX+1]; + size_t length; + + sd_event_source *event_source; + ++ char *state_file; ++ + LIST_FIELDS(StdoutStream, stdout_stream); + }; + ++void stdout_stream_free(StdoutStream *s) { ++ if (!s) ++ return; ++ ++ if (s->server) { ++ assert(s->server->n_stdout_streams > 0); ++ s->server->n_stdout_streams --; ++ LIST_REMOVE(stdout_stream, s->server->stdout_streams, s); ++ } ++ ++ if (s->event_source) { ++ sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF); ++ s->event_source = sd_event_source_unref(s->event_source); ++ } ++ ++ safe_close(s->fd); ++ free(s->label); ++ free(s->identifier); ++ free(s->unit_id); ++ free(s->state_file); ++ ++ free(s); ++} ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free); ++ ++static void stdout_stream_destroy(StdoutStream *s) { ++ if (!s) ++ return; ++ ++ if (s->state_file) ++ unlink(s->state_file); ++ ++ stdout_stream_free(s); ++} ++ ++static int stdout_stream_save(StdoutStream *s) { ++ _cleanup_free_ char *temp_path = NULL; ++ _cleanup_fclose_ FILE *f = NULL; ++ int r; ++ ++ assert(s); ++ ++ if (s->state != STDOUT_STREAM_RUNNING) ++ return 0; ++ ++ if (!s->state_file) { ++ struct stat st; ++ ++ r = fstat(s->fd, &st); ++ if (r < 0) ++ return log_warning_errno(errno, "Failed to stat connected stream: %m"); ++ ++ /* We use device and inode numbers as identifier for the stream */ ++ if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0) ++ return log_oom(); ++ } ++ ++ mkdir_p("/run/systemd/journal/streams", 0755); ++ ++ r = fopen_temporary(s->state_file, &f, &temp_path); ++ if (r < 0) ++ goto finish; ++ ++ fprintf(f, ++ "# This is private data. Do not parse\n" ++ "PRIORITY=%i\n" ++ "LEVEL_PREFIX=%i\n" ++ "FORWARD_TO_SYSLOG=%i\n" ++ "FORWARD_TO_KMSG=%i\n" ++ "FORWARD_TO_CONSOLE=%i\n", ++ s->priority, ++ s->level_prefix, ++ s->forward_to_syslog, ++ s->forward_to_kmsg, ++ s->forward_to_console); ++ ++ if (!isempty(s->identifier)) { ++ _cleanup_free_ char *escaped; ++ ++ escaped = cescape(s->identifier); ++ if (!escaped) { ++ r = -ENOMEM; ++ goto finish; ++ } ++ ++ fprintf(f, "IDENTIFIER=%s\n", escaped); ++ } ++ ++ if (!isempty(s->unit_id)) { ++ _cleanup_free_ char *escaped; ++ ++ escaped = cescape(s->unit_id); ++ if (!escaped) { ++ r = -ENOMEM; ++ goto finish; ++ } ++ ++ fprintf(f, "UNIT=%s\n", escaped); ++ } ++ ++ r = fflush_and_check(f); ++ if (r < 0) ++ goto finish; ++ ++ if (rename(temp_path, s->state_file) < 0) { ++ r = -errno; ++ goto finish; ++ } ++ ++ free(temp_path); ++ temp_path = NULL; ++ ++ /* Store the connection fd in PID 1, so that we get it passed ++ * in again on next start */ ++ if (!s->fdstore) { ++ sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1); ++ s->fdstore = true; ++ } ++ ++finish: ++ if (temp_path) ++ unlink(temp_path); ++ ++ if (r < 0) ++ log_error_errno(r, "Failed to save stream data %s: %m", s->state_file); ++ ++ return r; ++} ++ + static int stdout_stream_log(StdoutStream *s, const char *p) { + struct iovec iovec[N_IOVEC_META_FIELDS + 5]; + int priority; +@@ -219,6 +356,9 @@ static int stdout_stream_line(StdoutStream *s, char *p) { + + s->forward_to_console = !!r; + s->state = STDOUT_STREAM_RUNNING; ++ ++ /* Try to save the stream, so that journald can be restarted and we can recover */ ++ (void) stdout_stream_save(s); + return 0; + + case STDOUT_STREAM_RUNNING: +@@ -313,36 +453,62 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, + return 1; + + terminate: +- stdout_stream_free(s); ++ stdout_stream_destroy(s); + return 0; + } + +-void stdout_stream_free(StdoutStream *s) { ++static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { ++ _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL; ++ int r; ++ + assert(s); ++ assert(fd >= 0); + +- if (s->server) { +- assert(s->server->n_stdout_streams > 0); +- s->server->n_stdout_streams --; +- LIST_REMOVE(stdout_stream, s->server->stdout_streams, s); +- } ++ stream = new0(StdoutStream, 1); ++ if (!stream) ++ return log_oom(); + +- if (s->event_source) { +- sd_event_source_set_enabled(s->event_source, SD_EVENT_OFF); +- s->event_source = sd_event_source_unref(s->event_source); ++ stream->fd = -1; ++ stream->priority = LOG_INFO; ++ ++ r = getpeercred(fd, &stream->ucred); ++ if (r < 0) ++ return log_error_errno(r, "Failed to determine peer credentials: %m"); ++ ++ if (mac_selinux_use()) { ++ r = getpeersec(fd, &stream->label); ++ if (r < 0 && r != -EOPNOTSUPP) ++ (void) log_warning_errno(r, "Failed to determine peer security context: %m"); + } + +- safe_close(s->fd); ++ (void) shutdown(fd, SHUT_WR); + +- free(s->label); +- free(s->identifier); +- free(s->unit_id); +- free(s); ++ r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add stream to event loop: %m"); ++ ++ r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5); ++ if (r < 0) ++ return log_error_errno(r, "Failed to adjust stdout event source priority: %m"); ++ ++ stream->fd = fd; ++ ++ stream->server = s; ++ LIST_PREPEND(stdout_stream, s->stdout_streams, stream); ++ s->n_stdout_streams ++; ++ ++ if (ret) ++ *ret = stream; ++ ++ stream = NULL; ++ ++ return 0; + } + + static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revents, void *userdata) { ++ _cleanup_close_ int fd = -1; + Server *s = userdata; +- StdoutStream *stream; +- int fd, r; ++ int r; + + assert(s); + +@@ -362,61 +528,163 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent + + if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) { + log_warning("Too many stdout streams, refusing connection."); +- safe_close(fd); + return 0; + } + +- stream = new0(StdoutStream, 1); +- if (!stream) { +- safe_close(fd); +- return log_oom(); ++ r = stdout_stream_install(s, fd, NULL); ++ if (r < 0) ++ return r; ++ ++ fd = -1; ++ return 0; ++} ++ ++static int stdout_stream_load(StdoutStream *stream, const char *fname) { ++ _cleanup_free_ char ++ *priority = NULL, ++ *level_prefix = NULL, ++ *forward_to_syslog = NULL, ++ *forward_to_kmsg = NULL, ++ *forward_to_console = NULL; ++ int r; ++ ++ assert(stream); ++ assert(fname); ++ ++ if (!stream->state_file) { ++ stream->state_file = strappend("/run/systemd/journal/streams/", fname); ++ if (!stream->state_file) ++ return log_oom(); + } + +- stream->fd = fd; ++ r = parse_env_file(stream->state_file, NEWLINE, ++ "PRIORITY", &priority, ++ "LEVEL_PREFIX", &level_prefix, ++ "FORWARD_TO_SYSLOG", &forward_to_syslog, ++ "FORWARD_TO_KMSG", &forward_to_kmsg, ++ "FORWARD_TO_CONSOLE", &forward_to_console, ++ "IDENTIFIER", &stream->identifier, ++ "UNIT", &stream->unit_id, ++ NULL); ++ if (r < 0) ++ return log_error_errno(r, "Failed to read: %s", stream->state_file); + +- r = getpeercred(fd, &stream->ucred); +- if (r < 0) { +- log_error_errno(errno, "Failed to determine peer credentials: %m"); +- goto fail; ++ if (priority) { ++ int p; ++ ++ p = log_level_from_string(priority); ++ if (p >= 0) ++ stream->priority = p; + } + +-#ifdef HAVE_SELINUX +- if (mac_selinux_use()) { +- r = getpeersec(fd, &stream->label); +- if (r < 0 && r != -EOPNOTSUPP) +- (void) log_warning_errno(r, "Failed to determine peer security context: %m"); ++ if (level_prefix) { ++ r = parse_boolean(level_prefix); ++ if (r >= 0) ++ stream->level_prefix = r; + } +-#endif + +- if (shutdown(fd, SHUT_WR) < 0) { +- log_error_errno(errno, "Failed to shutdown writing side of socket: %m"); +- goto fail; ++ if (forward_to_syslog) { ++ r = parse_boolean(forward_to_syslog); ++ if (r >= 0) ++ stream->forward_to_syslog = r; + } + +- r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream); +- if (r < 0) { +- log_error_errno(r, "Failed to add stream to event loop: %m"); +- goto fail; ++ if (forward_to_kmsg) { ++ r = parse_boolean(forward_to_kmsg); ++ if (r >= 0) ++ stream->forward_to_kmsg = r; + } + +- r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5); +- if (r < 0) { +- log_error_errno(r, "Failed to adjust stdout event source priority: %m"); +- goto fail; ++ if (forward_to_console) { ++ r = parse_boolean(forward_to_console); ++ if (r >= 0) ++ stream->forward_to_console = r; + } + +- stream->server = s; +- LIST_PREPEND(stdout_stream, s->stdout_streams, stream); +- s->n_stdout_streams ++; ++ return 0; ++} ++ ++static int stdout_stream_restore(Server *s, const char *fname, int fd) { ++ StdoutStream *stream; ++ int r; ++ ++ assert(s); ++ assert(fname); ++ assert(fd >= 0); ++ ++ if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) { ++ log_warning("Too many stdout streams, refusing restoring of stream."); ++ return -ENOBUFS; ++ } ++ ++ r = stdout_stream_install(s, fd, &stream); ++ if (r < 0) ++ return r; ++ ++ stream->state = STDOUT_STREAM_RUNNING; ++ stream->fdstore = true; ++ ++ /* Ignore all parsing errors */ ++ (void) stdout_stream_load(stream, fname); + + return 0; ++} ++ ++static int server_restore_streams(Server *s, FDSet *fds) { ++ _cleanup_closedir_ DIR *d = NULL; ++ struct dirent *de; ++ int r; ++ ++ d = opendir("/run/systemd/journal/streams"); ++ if (!d) { ++ if (errno == ENOENT) ++ return 0; ++ ++ return log_warning_errno(errno, "Failed to enumerate /run/systemd/journal/streams: %m"); ++ } ++ ++ FOREACH_DIRENT(de, d, goto fail) { ++ unsigned long st_dev, st_ino; ++ bool found = false; ++ Iterator i; ++ int fd; ++ ++ if (sscanf(de->d_name, "%lu:%lu", &st_dev, &st_ino) != 2) ++ continue; ++ ++ FDSET_FOREACH(fd, fds, i) { ++ struct stat st; ++ ++ if (fstat(fd, &st) < 0) ++ return log_error_errno(errno, "Failed to stat %s: %m", de->d_name); ++ ++ if (S_ISSOCK(st.st_mode) && st.st_dev == st_dev && st.st_ino == st_ino) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ /* No file descriptor? Then let's delete the state file */ ++ log_debug("Cannot restore stream file %s", de->d_name); ++ unlinkat(dirfd(d), de->d_name, 0); ++ continue; ++ } ++ ++ fdset_remove(fds, fd); ++ ++ r = stdout_stream_restore(s, de->d_name, fd); ++ if (r < 0) ++ safe_close(fd); ++ } + +-fail: +- stdout_stream_free(stream); + return 0; ++ ++fail: ++ return log_error_errno(errno, "Failed to read streams directory: %m"); + } + +-int server_open_stdout_socket(Server *s) { ++int server_open_stdout_socket(Server *s, FDSet *fds) { + int r; + + assert(s); +@@ -452,5 +720,8 @@ int server_open_stdout_socket(Server *s) { + if (r < 0) + return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m"); + ++ /* Try to restore streams, but don't bother if this fails */ ++ (void) server_restore_streams(s, fds); ++ + return 0; + } +diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h +index 8cad01296..94bf955d7 100644 +--- a/src/journal/journald-stream.h ++++ b/src/journal/journald-stream.h +@@ -21,8 +21,9 @@ + along with systemd; If not, see . + ***/ + ++#include "fdset.h" + #include "journald-server.h" + +-int server_open_stdout_socket(Server *s); ++int server_open_stdout_socket(Server *s, FDSet *fds); + + void stdout_stream_free(StdoutStream *s); diff --git a/SOURCES/0521-journald-make-sure-we-retain-all-stream-fds-across-r.patch b/SOURCES/0521-journald-make-sure-we-retain-all-stream-fds-across-r.patch new file mode 100644 index 0000000..e3e9898 --- /dev/null +++ b/SOURCES/0521-journald-make-sure-we-retain-all-stream-fds-across-r.patch @@ -0,0 +1,34 @@ +From ad2d5449dc86ac37460ac9c16e0d5d088befbd0b Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 17 Jul 2017 10:04:37 +0200 +Subject: [PATCH] journald: make sure we retain all stream fds across restarts + (#6348) + +Currently we set 4096 as maximum for number of stream connections that +we accept. However maximum number of file descriptors that systemd is +willing to accept from us is just 1024. This means we can't retain all +stream connections that we accepted. Hence bump the limit of fds in a +unit file so that systemd holds open all stream fds while we are +restarted. + +New limit is set to 4224 (4096 + 128). + +(cherry picked from commit 3c978aca69e0e43d4dd453437ec9c498ea788795) + +Related: #1359939 +--- + units/systemd-journald.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index c85c34932..0d1ea61fe 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -20,6 +20,7 @@ ExecStart=@rootlibexecdir@/systemd-journald + Restart=always + RestartSec=0 + StandardOutput=null ++FileDescriptorStoreMax=4224 + 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=3min + diff --git a/SOURCES/0522-Allow-systemd-tmpfiles-to-set-the-file-directory-att.patch b/SOURCES/0522-Allow-systemd-tmpfiles-to-set-the-file-directory-att.patch new file mode 100644 index 0000000..1c9c72d --- /dev/null +++ b/SOURCES/0522-Allow-systemd-tmpfiles-to-set-the-file-directory-att.patch @@ -0,0 +1,218 @@ +From 037b80886a6c3acad294aee139d28d1f574d82cc Mon Sep 17 00:00:00 2001 +From: Goffredo Baroncelli +Date: Mon, 16 Mar 2015 20:33:50 +0100 +Subject: [PATCH] Allow systemd-tmpfiles to set the file/directory attributes + +Allow systemd-tmpfiles to set the file/directory attributes, like +chattr(1) does. Two more commands are added: 'H' and 'h' to set the +attributes, recursively and not. + +(cherry picked from commit 22c3a6cadbc99ad623501db9a928f52f6f84c0c3) + +Related: #1299714 +--- + src/tmpfiles/tmpfiles.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 150 insertions(+) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index ed35b8cf0..c8c56c722 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + #include "log.h" + #include "util.h" +@@ -91,6 +92,8 @@ typedef enum ItemType { + RELABEL_PATH = 'z', + RECURSIVE_RELABEL_PATH = 'Z', + ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */ ++ SET_ATTRIB = 'h', ++ RECURSIVE_SET_ATTRIB = 'H', + } ItemType; + + typedef struct Item { +@@ -109,12 +112,15 @@ typedef struct Item { + usec_t age; + + dev_t major_minor; ++ unsigned long attrib_value; ++ unsigned long attrib_mask; + + bool uid_set:1; + bool gid_set:1; + bool mode_set:1; + bool age_set:1; + bool mask_perms:1; ++ bool attrib_set:1; + + bool keep_first_level:1; + +@@ -817,6 +823,127 @@ static int path_set_acls(Item *item, const char *path) { + return r; + } + ++#define ALL_ATTRIBS \ ++ FS_NOATIME_FL | \ ++ FS_SYNC_FL | \ ++ FS_DIRSYNC_FL | \ ++ FS_APPEND_FL | \ ++ FS_COMPR_FL | \ ++ FS_NODUMP_FL | \ ++ FS_EXTENT_FL | \ ++ FS_IMMUTABLE_FL | \ ++ FS_JOURNAL_DATA_FL | \ ++ FS_SECRM_FL | \ ++ FS_UNRM_FL | \ ++ FS_NOTAIL_FL | \ ++ FS_TOPDIR_FL | \ ++ FS_NOCOW_FL ++ ++static int get_attrib_from_arg(Item *item) { ++ static const unsigned attributes[] = { ++ [(uint8_t)'A'] = FS_NOATIME_FL, /* do not update atime */ ++ [(uint8_t)'S'] = FS_SYNC_FL, /* Synchronous updates */ ++ [(uint8_t)'D'] = FS_DIRSYNC_FL, /* dirsync behaviour (directories only) */ ++ [(uint8_t)'a'] = FS_APPEND_FL, /* writes to file may only append */ ++ [(uint8_t)'c'] = FS_COMPR_FL, /* Compress file */ ++ [(uint8_t)'d'] = FS_NODUMP_FL, /* do not dump file */ ++ [(uint8_t)'e'] = FS_EXTENT_FL, /* Top of directory hierarchies*/ ++ [(uint8_t)'i'] = FS_IMMUTABLE_FL, /* Immutable file */ ++ [(uint8_t)'j'] = FS_JOURNAL_DATA_FL, /* Reserved for ext3 */ ++ [(uint8_t)'s'] = FS_SECRM_FL, /* Secure deletion */ ++ [(uint8_t)'u'] = FS_UNRM_FL, /* Undelete */ ++ [(uint8_t)'t'] = FS_NOTAIL_FL, /* file tail should not be merged */ ++ [(uint8_t)'T'] = FS_TOPDIR_FL, /* Top of directory hierarchies*/ ++ [(uint8_t)'C'] = FS_NOCOW_FL, /* Do not cow file */ ++ }; ++ char *p = item->argument; ++ enum { ++ MODE_ADD, ++ MODE_DEL, ++ MODE_SET ++ } mode = MODE_ADD; ++ unsigned long value = 0, mask = 0; ++ ++ if (!p) { ++ log_error("\"%s\": setting ATTR need an argument", item->path); ++ return -EINVAL; ++ } ++ ++ if (*p == '+') { ++ mode = MODE_ADD; ++ p++; ++ } else if (*p == '-') { ++ mode = MODE_DEL; ++ p++; ++ } else if (*p == '=') { ++ mode = MODE_SET; ++ p++; ++ } ++ ++ if (!*p && mode != MODE_SET) { ++ log_error("\"%s\": setting ATTR: argument is empty", item->path); ++ return -EINVAL; ++ } ++ for (; *p ; p++) { ++ if ((uint8_t)*p > ELEMENTSOF(attributes) || attributes[(uint8_t)*p] == 0) { ++ log_error("\"%s\": setting ATTR: unknown attr '%c'", item->path, *p); ++ return -EINVAL; ++ } ++ if (mode == MODE_ADD || mode == MODE_SET) ++ value |= attributes[(uint8_t)*p]; ++ else ++ value &= ~attributes[(uint8_t)*p]; ++ mask |= attributes[(uint8_t)*p]; ++ } ++ ++ if (mode == MODE_SET) ++ mask |= ALL_ATTRIBS; ++ ++ assert(mask); ++ ++ item->attrib_mask = mask; ++ item->attrib_value = value; ++ item->attrib_set = true; ++ ++ return 0; ++ ++} ++ ++static int path_set_attrib(Item *item, const char *path) { ++ _cleanup_close_ int fd = -1; ++ int r; ++ unsigned f; ++ struct stat st; ++ ++ /* do nothing */ ++ if (item->attrib_mask == 0 || !item->attrib_set) ++ return 0; ++ /* ++ * It is OK to ignore an lstat() error, because the error ++ * will be catch by the open() below anyway ++ */ ++ if (lstat(path, &st) == 0 && ++ !S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) { ++ return 0; ++ } ++ ++ fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC); ++ ++ if (fd < 0) ++ return log_error_errno(errno, "Cannot open \"%s\": %m", path); ++ ++ f = item->attrib_value & item->attrib_mask; ++ if (!S_ISDIR(st.st_mode)) ++ f &= ~FS_DIRSYNC_FL; ++ r = change_attr_fd(fd, f, item->attrib_mask); ++ if (r < 0) ++ return log_error_errno(errno, ++ "Cannot set attrib for \"%s\", value=0x%08lx, mask=0x%08lx: %m", ++ path, item->attrib_value, item->attrib_mask); ++ ++ return 0; ++} ++ + static int write_one_file(Item *i, const char *path) { + _cleanup_close_ int fd = -1; + int flags, r = 0; +@@ -1266,6 +1393,18 @@ static int create_item(Item *i) { + if (r < 0) + return r; + break; ++ ++ case SET_ATTRIB: ++ r = glob_item(i, path_set_attrib, false); ++ if (r < 0) ++ return r; ++ break; ++ ++ case RECURSIVE_SET_ATTRIB: ++ r = glob_item(i, path_set_attrib, true); ++ if (r < 0) ++ return r; ++ break; + } + + return 0; +@@ -1712,6 +1851,17 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + return r; + break; + ++ case SET_ATTRIB: ++ case RECURSIVE_SET_ATTRIB: ++ if (!i.argument) { ++ log_error("[%s:%u] Set attrib requires argument.", fname, line); ++ return -EBADMSG; ++ } ++ r = get_attrib_from_arg(&i); ++ if (r < 0) ++ return r; ++ break; ++ + default: + log_error("[%s:%u] Unknown command type '%c'.", fname, line, (char) i.type); + return -EBADMSG; diff --git a/SOURCES/0523-tmpfiles-rework-file-attribute-code.patch b/SOURCES/0523-tmpfiles-rework-file-attribute-code.patch new file mode 100644 index 0000000..50dee6c --- /dev/null +++ b/SOURCES/0523-tmpfiles-rework-file-attribute-code.patch @@ -0,0 +1,326 @@ +From 3a68810cd6ac23f7107491ab6e1fbd565ed52bf0 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 8 Apr 2015 22:35:52 +0200 +Subject: [PATCH] tmpfiles: rework file attribute code + +- Stick to one type for the flags field: unsigned. This appears to be + what the kernel uses, and there's no point in using something else. + +- compress the flags array by avoiding sparse entries + +- extend some error messages to not use abbreviated words + +- avoid TTOCTTOU issues by invoking fstat() after open() when applying + file flags + +- add explanation why we need to check the file type with fstat(). + +- don't needlessly abbreviate "attribute" as "attrib", in particually as + "chattr" abbreviates it as "attr" rather than "attrib". + +(cherry picked from commit 88ec4dfa289cd97496dbb9670365a3d4be13d41c) + +Conflicts: + src/tmpfiles/tmpfiles.c + +Related: #1299714 +--- + src/tmpfiles/tmpfiles.c | 207 ++++++++++++++++++++++++++---------------------- + 1 file changed, 114 insertions(+), 93 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index c8c56c722..800e620bc 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -92,8 +92,8 @@ typedef enum ItemType { + RELABEL_PATH = 'z', + RECURSIVE_RELABEL_PATH = 'Z', + ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */ +- SET_ATTRIB = 'h', +- RECURSIVE_SET_ATTRIB = 'H', ++ SET_ATTRIBUTE = 'h', ++ RECURSIVE_SET_ATTRIBUTE = 'H', + } ItemType; + + typedef struct Item { +@@ -112,15 +112,15 @@ typedef struct Item { + usec_t age; + + dev_t major_minor; +- unsigned long attrib_value; +- unsigned long attrib_mask; ++ unsigned attribute_value; ++ unsigned attribute_mask; + + bool uid_set:1; + bool gid_set:1; + bool mode_set:1; + bool age_set:1; + bool mask_perms:1; +- bool attrib_set:1; ++ bool attribute_set:1; + + bool keep_first_level:1; + +@@ -823,123 +823,144 @@ static int path_set_acls(Item *item, const char *path) { + return r; + } + +-#define ALL_ATTRIBS \ +- FS_NOATIME_FL | \ +- FS_SYNC_FL | \ +- FS_DIRSYNC_FL | \ +- FS_APPEND_FL | \ +- FS_COMPR_FL | \ +- FS_NODUMP_FL | \ +- FS_EXTENT_FL | \ +- FS_IMMUTABLE_FL | \ +- FS_JOURNAL_DATA_FL | \ +- FS_SECRM_FL | \ +- FS_UNRM_FL | \ +- FS_NOTAIL_FL | \ +- FS_TOPDIR_FL | \ +- FS_NOCOW_FL +- +-static int get_attrib_from_arg(Item *item) { +- static const unsigned attributes[] = { +- [(uint8_t)'A'] = FS_NOATIME_FL, /* do not update atime */ +- [(uint8_t)'S'] = FS_SYNC_FL, /* Synchronous updates */ +- [(uint8_t)'D'] = FS_DIRSYNC_FL, /* dirsync behaviour (directories only) */ +- [(uint8_t)'a'] = FS_APPEND_FL, /* writes to file may only append */ +- [(uint8_t)'c'] = FS_COMPR_FL, /* Compress file */ +- [(uint8_t)'d'] = FS_NODUMP_FL, /* do not dump file */ +- [(uint8_t)'e'] = FS_EXTENT_FL, /* Top of directory hierarchies*/ +- [(uint8_t)'i'] = FS_IMMUTABLE_FL, /* Immutable file */ +- [(uint8_t)'j'] = FS_JOURNAL_DATA_FL, /* Reserved for ext3 */ +- [(uint8_t)'s'] = FS_SECRM_FL, /* Secure deletion */ +- [(uint8_t)'u'] = FS_UNRM_FL, /* Undelete */ +- [(uint8_t)'t'] = FS_NOTAIL_FL, /* file tail should not be merged */ +- [(uint8_t)'T'] = FS_TOPDIR_FL, /* Top of directory hierarchies*/ +- [(uint8_t)'C'] = FS_NOCOW_FL, /* Do not cow file */ ++#define ATTRIBUTES_ALL \ ++ (FS_NOATIME_FL | \ ++ FS_SYNC_FL | \ ++ FS_DIRSYNC_FL | \ ++ FS_APPEND_FL | \ ++ FS_COMPR_FL | \ ++ FS_NODUMP_FL | \ ++ FS_EXTENT_FL | \ ++ FS_IMMUTABLE_FL | \ ++ FS_JOURNAL_DATA_FL | \ ++ FS_SECRM_FL | \ ++ FS_UNRM_FL | \ ++ FS_NOTAIL_FL | \ ++ FS_TOPDIR_FL | \ ++ FS_NOCOW_FL) ++ ++static int get_attribute_from_arg(Item *item) { ++ ++ static const struct { ++ char character; ++ unsigned value; ++ } attributes[] = { ++ { 'A', FS_NOATIME_FL }, /* do not update atime */ ++ { 'S', FS_SYNC_FL }, /* Synchronous updates */ ++ { 'D', FS_DIRSYNC_FL }, /* dirsync behaviour (directories only) */ ++ { 'a', FS_APPEND_FL }, /* writes to file may only append */ ++ { 'c', FS_COMPR_FL }, /* Compress file */ ++ { 'd', FS_NODUMP_FL }, /* do not dump file */ ++ { 'e', FS_EXTENT_FL }, /* Top of directory hierarchies*/ ++ { 'i', FS_IMMUTABLE_FL }, /* Immutable file */ ++ { 'j', FS_JOURNAL_DATA_FL }, /* Reserved for ext3 */ ++ { 's', FS_SECRM_FL }, /* Secure deletion */ ++ { 'u', FS_UNRM_FL }, /* Undelete */ ++ { 't', FS_NOTAIL_FL }, /* file tail should not be merged */ ++ { 'T', FS_TOPDIR_FL }, /* Top of directory hierarchies*/ ++ { 'C', FS_NOCOW_FL }, /* Do not cow file */ + }; +- char *p = item->argument; ++ + enum { + MODE_ADD, + MODE_DEL, + MODE_SET + } mode = MODE_ADD; +- unsigned long value = 0, mask = 0; + +- if (!p) { +- log_error("\"%s\": setting ATTR need an argument", item->path); +- return -EINVAL; +- } ++ unsigned value = 0, mask = 0; ++ const char *p; + +- if (*p == '+') { +- mode = MODE_ADD; +- p++; +- } else if (*p == '-') { +- mode = MODE_DEL; +- p++; +- } else if (*p == '=') { +- mode = MODE_SET; +- p++; ++ assert(item); ++ ++ p = item->argument; ++ if (p) { ++ if (*p == '+') { ++ mode = MODE_ADD; ++ p++; ++ } else if (*p == '-') { ++ mode = MODE_DEL; ++ p++; ++ } else if (*p == '=') { ++ mode = MODE_SET; ++ p++; ++ } + } + +- if (!*p && mode != MODE_SET) { +- log_error("\"%s\": setting ATTR: argument is empty", item->path); ++ if (isempty(p) && mode != MODE_SET) { ++ log_error("Setting file attribute on '%s' needs an attribute specification.", item->path); + return -EINVAL; + } +- for (; *p ; p++) { +- if ((uint8_t)*p > ELEMENTSOF(attributes) || attributes[(uint8_t)*p] == 0) { +- log_error("\"%s\": setting ATTR: unknown attr '%c'", item->path, *p); ++ ++ for (; p && *p ; p++) { ++ unsigned i, v; ++ ++ for (i = 0; i < ELEMENTSOF(attributes); i++) ++ if (*p == attributes[i].character) ++ break; ++ ++ if (i >= ELEMENTSOF(attributes)) { ++ log_error("Unknown file attribute '%c' on '%s'.", *p, item->path); + return -EINVAL; + } ++ ++ v = attributes[i].value; ++ + if (mode == MODE_ADD || mode == MODE_SET) +- value |= attributes[(uint8_t)*p]; ++ value |= v; + else +- value &= ~attributes[(uint8_t)*p]; +- mask |= attributes[(uint8_t)*p]; ++ value &= ~v; ++ ++ mask |= v; + } + + if (mode == MODE_SET) +- mask |= ALL_ATTRIBS; ++ mask |= ATTRIBUTES_ALL; + +- assert(mask); ++ assert(mask != 0); + +- item->attrib_mask = mask; +- item->attrib_value = value; +- item->attrib_set = true; ++ item->attribute_mask = mask; ++ item->attribute_value = value; ++ item->attribute_set = true; + + return 0; +- + } + +-static int path_set_attrib(Item *item, const char *path) { ++static int path_set_attribute(Item *item, const char *path) { + _cleanup_close_ int fd = -1; +- int r; +- unsigned f; + struct stat st; ++ unsigned f; ++ int r; + +- /* do nothing */ +- if (item->attrib_mask == 0 || !item->attrib_set) +- return 0; +- /* +- * It is OK to ignore an lstat() error, because the error +- * will be catch by the open() below anyway +- */ +- if (lstat(path, &st) == 0 && +- !S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) { ++ if (!item->attribute_set || item->attribute_mask == 0) + return 0; +- } + + fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC); + + if (fd < 0) +- return log_error_errno(errno, "Cannot open \"%s\": %m", path); ++ return log_error_errno(errno, "Cannot open '%s': %m", path); + +- f = item->attrib_value & item->attrib_mask; ++ if (fstat(fd, &st) < 0) ++ return log_error_errno(errno, "Cannot stat '%s': %m", path); ++ ++ /* Issuing the file attribute ioctls on device nodes is not ++ * safe, as that will be delivered to the drivers, not the ++ * file system containing the device node. */ ++ if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) { ++ log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path); ++ return -EINVAL; ++ } ++ ++ f = item->attribute_value & item->attribute_mask; ++ ++ /* Mask away directory-specific flags */ + if (!S_ISDIR(st.st_mode)) + f &= ~FS_DIRSYNC_FL; +- r = change_attr_fd(fd, f, item->attrib_mask); ++ ++ r = chattr_fd(fd, f, item->attribute_mask); + if (r < 0) +- return log_error_errno(errno, +- "Cannot set attrib for \"%s\", value=0x%08lx, mask=0x%08lx: %m", +- path, item->attrib_value, item->attrib_mask); ++ return log_error_errno(r, ++ "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m", ++ path, item->attribute_value, item->attribute_mask); + + return 0; + } +@@ -1394,14 +1415,14 @@ static int create_item(Item *i) { + return r; + break; + +- case SET_ATTRIB: +- r = glob_item(i, path_set_attrib, false); ++ case SET_ATTRIBUTE: ++ r = glob_item(i, path_set_attribute, false); + if (r < 0) + return r; + break; + +- case RECURSIVE_SET_ATTRIB: +- r = glob_item(i, path_set_attrib, true); ++ case RECURSIVE_SET_ATTRIBUTE: ++ r = glob_item(i, path_set_attribute, true); + if (r < 0) + return r; + break; +@@ -1851,13 +1872,13 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + return r; + break; + +- case SET_ATTRIB: +- case RECURSIVE_SET_ATTRIB: ++ case SET_ATTRIBUTE: ++ case RECURSIVE_SET_ATTRIBUTE: + if (!i.argument) { +- log_error("[%s:%u] Set attrib requires argument.", fname, line); ++ log_error("[%s:%u] Set file attribute requires argument.", fname, line); + return -EBADMSG; + } +- r = get_attrib_from_arg(&i); ++ r = get_attribute_from_arg(&i); + if (r < 0) + return r; + break; diff --git a/SOURCES/0524-tmpfiles-warn-if-we-get-an-argument-on-lines-that-do.patch b/SOURCES/0524-tmpfiles-warn-if-we-get-an-argument-on-lines-that-do.patch new file mode 100644 index 0000000..bbd9364 --- /dev/null +++ b/SOURCES/0524-tmpfiles-warn-if-we-get-an-argument-on-lines-that-do.patch @@ -0,0 +1,40 @@ +From 95ee3c8f1ef9408543c962af5f21e01ccef544e1 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 7 Sep 2017 15:46:24 +0200 +Subject: [PATCH] tmpfiles: warn if we get an argument on lines that don't take + any + +(cherry picked from commit c82500c6fb37a25bc3c4b1e0be11a90a395619d9) + +Related: #1299714 +--- + src/tmpfiles/tmpfiles.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 800e620bc..70e0cc2fa 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1788,8 +1788,6 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + + switch (i.type) { + +- case CREATE_FILE: +- case TRUNCATE_FILE: + case CREATE_DIRECTORY: + case CREATE_SUBVOLUME: + case EMPTY_DIRECTORY: +@@ -1802,6 +1800,13 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + case ADJUST_MODE: + case RELABEL_PATH: + case RECURSIVE_RELABEL_PATH: ++ if (i.argument) ++ log_warning("[%s:%u] %c lines don't take argument field, ignoring.", fname, line, i.type); ++ ++ break; ++ ++ case CREATE_FILE: ++ case TRUNCATE_FILE: + break; + + case CREATE_SYMLINK: diff --git a/SOURCES/0525-tmpfiles-substitute-specifiers-in-arguments-for-writ.patch b/SOURCES/0525-tmpfiles-substitute-specifiers-in-arguments-for-writ.patch new file mode 100644 index 0000000..a4ba787 --- /dev/null +++ b/SOURCES/0525-tmpfiles-substitute-specifiers-in-arguments-for-writ.patch @@ -0,0 +1,207 @@ +From d23386f61d810dab77e9d9d9130adbd826ea823f Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 7 Sep 2017 15:49:08 +0200 +Subject: [PATCH] tmpfiles: substitute % specifiers in arguments for writing + files and xattrs + +(cherry-picked from commit bd550f78eb261c757cbff85acdb55563c56521f2) + +Related: #1299714 +--- + src/tmpfiles/tmpfiles.c | 79 ++++++++++++++++++++++++++----------------------- + 1 file changed, 42 insertions(+), 37 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 70e0cc2fa..ddb274fce 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -151,6 +151,14 @@ static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles"); + static Hashmap *items = NULL, *globs = NULL; + static Set *unix_sockets = NULL; + ++static const Specifier specifier_table[] = { ++ { 'm', specifier_machine_id, NULL }, ++ { 'b', specifier_boot_id, NULL }, ++ { 'H', specifier_host_name, NULL }, ++ { 'v', specifier_kernel_release, NULL }, ++ {} ++}; ++ + static bool needs_glob(ItemType t) { + return IN_SET(t, + WRITE_FILE, +@@ -657,8 +665,7 @@ static int path_set_perms(Item *i, const char *path) { + return label_fix(path, false, false); + } + +-static int get_xattrs_from_arg(Item *i) { +- char *xattr; ++static int parse_xattrs_from_arg(Item *i) { + const char *p; + int r; + +@@ -667,35 +674,37 @@ static int get_xattrs_from_arg(Item *i) { + + p = i->argument; + +- while ((r = unquote_first_word(&p, &xattr, false)) > 0) { +- _cleanup_free_ char *tmp = NULL, *name = NULL, +- *value = NULL, *value2 = NULL, *_xattr = xattr; ++ for (;;) { ++ _cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL, *xattr_replaced = NULL; ++ ++ r = unquote_first_word(&p, &xattr, false); ++ if (r < 0) ++ log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p); ++ if (r <= 0) ++ break; ++ ++ r = specifier_printf(xattr, specifier_table, NULL, &xattr_replaced); ++ if (r < 0) ++ return log_error_errno(r, "Failed to replace specifiers in extended attribute '%s': %m", xattr); + +- r = split_pair(xattr, "=", &name, &value); ++ r = split_pair(xattr_replaced, "=", &name, &value); + if (r < 0) { + log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr); + continue; + } + +- if (strempty(name) || strempty(value)) { +- log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr); ++ if (isempty(name) || isempty(value)) { ++ log_warning("Malformed extended attribute found, ignoring: %s", xattr); + continue; + } + +- tmp = unquote(value, "\""); +- if (!tmp) +- return log_oom(); +- +- value2 = cunescape(tmp); +- if (!value2) ++ if (strv_push_pair(&i->xattrs, name, value) < 0) + return log_oom(); + +- if (strv_push_pair(&i->xattrs, name, value2) < 0) +- return log_oom(); +- name = value2 = NULL; ++ name = value = NULL; + } + +- return r; ++ return 0; + } + + static int path_set_xattrs(Item *i, const char *path) { +@@ -708,17 +717,16 @@ static int path_set_xattrs(Item *i, const char *path) { + int n; + + n = strlen(*value); +- log_debug("\"%s\": setting xattr \"%s=%s\"", path, *name, *value); ++ log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path); + if (lsetxattr(path, *name, *value, n, 0) < 0) { +- log_error("Setting extended attribute %s=%s on %s failed: %m", +- *name, *value, path); ++ log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path); + return -errno; + } + } + return 0; + } + +-static int get_acls_from_arg(Item *item) { ++static int parse_acls_from_arg(Item *item) { + #ifdef HAVE_ACL + int r; + +@@ -726,6 +734,7 @@ static int get_acls_from_arg(Item *item) { + + /* If force (= modify) is set, we will not modify the acl + * afterwards, so the mask can be added now if necessary. */ ++ + r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force); + if (r < 0) + log_warning_errno(r, "Failed to parse ACL \"%s\": %m. Ignoring", +@@ -839,7 +848,7 @@ static int path_set_acls(Item *item, const char *path) { + FS_TOPDIR_FL | \ + FS_NOCOW_FL) + +-static int get_attribute_from_arg(Item *item) { ++static int parse_attribute_from_arg(Item *item) { + + static const struct { + char character; +@@ -993,7 +1002,7 @@ static int write_one_file(Item *i, const char *path) { + } + + if (i->argument) { +- _cleanup_free_ char *unescaped; ++ _cleanup_free_ char *unescaped = NULL, *replaced = NULL; + + log_debug("%s to \"%s\".", + i->type == CREATE_FILE ? "Appending" : "Writing", path); +@@ -1002,7 +1011,11 @@ static int write_one_file(Item *i, const char *path) { + if (!unescaped) + return log_oom(); + +- r = loop_write(fd, unescaped, strlen(unescaped), false); ++ r = specifier_printf(unescaped, specifier_table, NULL, &replaced); ++ if (r < 0) ++ return log_error_errno(r, "Failed to replace specifiers in parameter to write '%s': %m", unescaped); ++ ++ r = loop_write(fd, replaced, strlen(replaced), false); + if (r < 0) + return log_error_errno(r, "Failed to write file \"%s\": %m", path); + } else +@@ -1712,14 +1725,6 @@ static bool should_include_path(const char *path) { + + static int parse_line(const char *fname, unsigned line, const char *buffer) { + +- static const Specifier specifier_table[] = { +- { 'm', specifier_machine_id, NULL }, +- { 'b', specifier_boot_id, NULL }, +- { 'H', specifier_host_name, NULL }, +- { 'v', specifier_kernel_release, NULL }, +- {} +- }; +- + _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL; + _cleanup_(item_free_contents) Item i = {}; + ItemArray *existing; +@@ -1801,7 +1806,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + case RELABEL_PATH: + case RECURSIVE_RELABEL_PATH: + if (i.argument) +- log_warning("[%s:%u] %c lines don't take argument field, ignoring.", fname, line, i.type); ++ log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname, line, i.type); + + break; + +@@ -1861,7 +1866,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + log_error("[%s:%u] Set extended attribute requires argument.", fname, line); + return -EBADMSG; + } +- r = get_xattrs_from_arg(&i); ++ r = parse_xattrs_from_arg(&i); + if (r < 0) + return r; + break; +@@ -1872,7 +1877,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + log_error("[%s:%u] Set ACLs requires argument.", fname, line); + return -EBADMSG; + } +- r = get_acls_from_arg(&i); ++ r = parse_acls_from_arg(&i); + if (r < 0) + return r; + break; +@@ -1883,7 +1888,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { + log_error("[%s:%u] Set file attribute requires argument.", fname, line); + return -EBADMSG; + } +- r = get_attribute_from_arg(&i); ++ r = parse_attribute_from_arg(&i); + if (r < 0) + return r; + break; diff --git a/SOURCES/0526-btrfs-util-introduce-btrfs_is_filesystem-and-make-us.patch b/SOURCES/0526-btrfs-util-introduce-btrfs_is_filesystem-and-make-us.patch new file mode 100644 index 0000000..1b4ed93 --- /dev/null +++ b/SOURCES/0526-btrfs-util-introduce-btrfs_is_filesystem-and-make-us.patch @@ -0,0 +1,105 @@ +From 81f0a57bed6e03eeaa24443d16555c7f5d20ee1a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 22 Apr 2015 13:08:19 +0200 +Subject: [PATCH] btrfs-util: introduce btrfs_is_filesystem() and make use of + it where appropriate + +Let's unify the code that checks whether an fd is on btrfs a bit. + +(Also, rename btrfs_is_snapshot() to btrfs_is_subvol(), since that's +usually how this is referred to in our code) + +(cherry picked from commit 21222ea5cdec65fa30a75bd5a78475459075b946) + +Related: #1299714 +--- + src/shared/btrfs-util.c | 23 ++++++++++++++++------- + src/shared/btrfs-util.h | 3 ++- + src/shared/machine-image.c | 9 ++++----- + 3 files changed, 22 insertions(+), 13 deletions(-) + +diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c +index b34ac8b15..52a214349 100644 +--- a/src/shared/btrfs-util.c ++++ b/src/shared/btrfs-util.c +@@ -83,10 +83,22 @@ static int extract_subvolume_name(const char *path, const char **subvolume) { + return 0; + } + +-int btrfs_is_snapshot(int fd) { +- struct stat st; ++int btrfs_is_filesystem(int fd) { + struct statfs sfs; + ++ assert(fd >= 0); ++ ++ if (fstatfs(fd, &sfs) < 0) ++ return -errno; ++ ++ return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); ++} ++ ++int btrfs_is_subvol(int fd) { ++ struct stat st; ++ ++ assert(fd >= 0); ++ + /* On btrfs subvolumes always have the inode 256 */ + + if (fstat(fd, &st) < 0) +@@ -95,10 +107,7 @@ int btrfs_is_snapshot(int fd) { + if (!S_ISDIR(st.st_mode) || st.st_ino != 256) + return 0; + +- if (fstatfs(fd, &sfs) < 0) +- return -errno; +- +- return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); ++ return btrfs_is_filesystem(fd); + } + + int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) { +@@ -115,7 +124,7 @@ int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_ + if (old_fd < 0) + return -errno; + +- r = btrfs_is_snapshot(old_fd); ++ r = btrfs_is_subvol(old_fd); + if (r < 0) + return r; + if (r == 0) { +diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h +index 1b9c142e5..1315def87 100644 +--- a/src/shared/btrfs-util.h ++++ b/src/shared/btrfs-util.h +@@ -43,7 +43,8 @@ typedef struct BtrfsQuotaInfo { + uint64_t exclusive_max; + } BtrfsQuotaInfo; + +-int btrfs_is_snapshot(int fd); ++int btrfs_is_filesystem(int fd); ++int btrfs_is_subvol(int fd); + + int btrfs_subvol_make(const char *path); + int btrfs_subvol_make_label(const char *path); +diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c +index c02ee814c..256622928 100644 +--- a/src/shared/machine-image.c ++++ b/src/shared/machine-image.c +@@ -136,12 +136,11 @@ static int image_make( + + /* btrfs subvolumes have inode 256 */ + if (st.st_ino == 256) { +- struct statfs sfs; + +- if (fstatfs(fd, &sfs) < 0) +- return -errno; +- +- if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) { ++ r = btrfs_is_filesystem(fd); ++ if (r < 0) ++ return r; ++ if (r) { + BtrfsSubvolInfo info; + BtrfsQuotaInfo quota; + diff --git a/SOURCES/0527-journal-don-t-force-FS_NOCOW_FL-on-new-journal-files.patch b/SOURCES/0527-journal-don-t-force-FS_NOCOW_FL-on-new-journal-files.patch new file mode 100644 index 0000000..ce36900 --- /dev/null +++ b/SOURCES/0527-journal-don-t-force-FS_NOCOW_FL-on-new-journal-files.patch @@ -0,0 +1,86 @@ +From 245ad27530ae9e99242ebfa1631bd7fc8f66a59c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 22 Apr 2015 13:20:49 +0200 +Subject: [PATCH] journal: don't force FS_NOCOW_FL on new journal files, but + warn if it is missing + +This way users have the freedom to set or unset the FS_NOCOW_FL flag on +their journal files by setting it on the journal directory. Since our +default tmpfiles configuration now sets this flag on the directory the +flag is set by default on new files, however people can opt-out of this +by masking the tmpfiles file for it. + +(cherry picked from commit fc68c92973e5437ee0489c1bc80d80f0a7b6ca0b) + +Conflicts: + src/journal/journal-file.c + +Resolves: #1299714 +--- + src/journal/journal-file.c | 46 ++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 36 insertions(+), 10 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 8034b771d..0fd59ec07 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -2543,6 +2543,41 @@ void journal_file_print_header(JournalFile *f) { + printf("Disk usage: %s\n", format_bytes(bytes, sizeof(bytes), (off_t) st.st_blocks * 512ULL)); + } + ++static int journal_file_warn_btrfs(JournalFile *f) { ++ unsigned attrs; ++ int r; ++ ++ assert(f); ++ ++ /* Before we write anything, check if the COW logic is turned ++ * off on btrfs. Given our write pattern that is quite ++ * unfriendly to COW file systems this should greatly improve ++ * performance on COW file systems, such as btrfs, at the ++ * expense of data integrity features (which shouldn't be too ++ * bad, given that we do our own checksumming). */ ++ ++ r = btrfs_is_filesystem(f->fd); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to determine if journal is on btrfs: %m"); ++ if (!r) ++ return 0; ++ ++ r = read_attr_fd(f->fd, &attrs); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to read file attributes: %m"); ++ ++ if (attrs & FS_NOCOW_FL) { ++ log_debug("Detected btrfs file system with copy-on-write disabled, all is good."); ++ return 0; ++ } ++ ++ log_notice("Creating journal file %s on a btrfs file system, and copy-on-write is enabled. " ++ "This is likely to slow down journal access substantially, please consider turning " ++ "off the copy-on-write file attribute on the journal directory, using chattr +C.", f->path); ++ ++ return 1; ++} ++ + int journal_file_open( + const char *fname, + int flags, +@@ -2623,16 +2658,7 @@ int journal_file_open( + + if (f->last_stat.st_size == 0 && f->writable) { + +- /* Before we write anything, turn off COW logic. Given +- * our write pattern that is quite unfriendly to COW +- * file systems this should greatly improve +- * performance on COW file systems, such as btrfs, at +- * the expense of data integrity features (which +- * shouldn't be too bad, given that we do our own +- * checksumming). */ +- r = chattr_fd(f->fd, true, FS_NOCOW_FL); +- if (r < 0 && r != -ENOTTY) +- log_warning_errno(r, "Failed to set file attributes: %m"); ++ (void) journal_file_warn_btrfs(f); + + /* Let's attach the creation time to the journal file, + * so that the vacuuming code knows the age of this diff --git a/SOURCES/0528-tmpfiles-Add-C-attrib-to-the-journal-files-directori.patch b/SOURCES/0528-tmpfiles-Add-C-attrib-to-the-journal-files-directori.patch new file mode 100644 index 0000000..0aeb0b1 --- /dev/null +++ b/SOURCES/0528-tmpfiles-Add-C-attrib-to-the-journal-files-directori.patch @@ -0,0 +1,64 @@ +From 3740b7a6d246a5860c8f1d96504bbf00692447e0 Mon Sep 17 00:00:00 2001 +From: Goffredo Baroncelli +Date: Sun, 12 Apr 2015 20:30:28 +0200 +Subject: [PATCH] tmpfiles: Add +C attrib to the journal files directories + +Add the +C file attribute (NOCOW) to the journal directories, so that +the flag is inherited automatically for new journal files created in +them. The journal write pattern is problematic on btrfs file systems as +it results in badly fragmented files when copy-on-write (COW) is used: +the performances decreases substantially over time. + +To avoid this issue, this tmpfile.d snippet sets the NOCOW attribute to +the journal files directories, so newly created journal files inherit +the NCOOW attribute that disables copy-on-write. + +Be aware that the NOCOW file attribute also disables btrfs checksumming +for these files, and thus prevents btrfs from rebuilding corrupted files +on a RAID filesystem. + +In a single disk filesystems (or filesystems without redundancy) it is +safe to use the NOCOW flags without drawbacks, since the journal files +contain their own checksumming. + +(cherry picked from commit 3a92e4ba470611ceec6693640b05eb248d62e32d) + +Related: #1299714 +--- + tmpfiles.d/journal-nocow.conf | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + create mode 100644 tmpfiles.d/journal-nocow.conf + +diff --git a/tmpfiles.d/journal-nocow.conf b/tmpfiles.d/journal-nocow.conf +new file mode 100644 +index 000000000..e7938c891 +--- /dev/null ++++ b/tmpfiles.d/journal-nocow.conf +@@ -0,0 +1,27 @@ ++# This file is part of systemd. ++# ++# systemd is free software; you can redistribute it and/or modify it ++# under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++ ++# See tmpfiles.d(5) for details ++ ++# Set the NOCOW attribute for directories of journal files. This flag ++# is inheredited by their new files and sub-directories. Matters only ++# for btrfs filesystems. ++# ++# WARNING: Enabling the NOCOW attribute improves journal performance ++# substantially, but also disables the btrfs checksum logic. In ++# btrfs RAID filesystems the checksums are needed for rebuilding ++# corrupted files. Without checksums such rebuilds are not ++# possible. ++# ++# In a single-disk filesystem (or a filesystem without redundancy) ++# enabling the NOCOW attribute for journal files is safe, because ++# they have their own checksums and a rebuilding wouldn't be possible ++# in any case. ++ ++h /var/log/journal - - - - +C ++h /var/log/journal/%m - - - - +C ++h /var/log/journal/remote - - - - +C diff --git a/SOURCES/0529-Revert-path-util-make-use-of-mnt_id-field-exported-i.patch b/SOURCES/0529-Revert-path-util-make-use-of-mnt_id-field-exported-i.patch new file mode 100644 index 0000000..c4e2bc0 --- /dev/null +++ b/SOURCES/0529-Revert-path-util-make-use-of-mnt_id-field-exported-i.patch @@ -0,0 +1,553 @@ +From f3d485e1034cdea60cab3c257e340dd9b3e48fc1 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Mon, 18 Sep 2017 10:13:05 +0200 +Subject: [PATCH] Revert "path-util: make use of "mnt_id" field exported in + /proc/self/fdinfo/" + +This reverts commit f63b66b6347a8d8e5e6930a939d1997bfd8e2e7c. +This implementation was not working becuase of misbehaving +canonicalize_file_name. + +Related: #1472439 +--- + src/core/automount.c | 2 +- + src/core/machine-id-setup.c | 2 +- + src/core/mount-setup.c | 2 +- + src/efi-boot-generator/efi-boot-generator.c | 2 +- + src/gpt-auto-generator/gpt-auto-generator.c | 2 +- + src/login/logind-user.c | 2 +- + src/nspawn/nspawn.c | 10 +- + src/shared/cgroup-util.c | 2 +- + src/shared/condition.c | 2 +- + src/shared/path-util.c | 209 ++++++---------------------- + src/shared/path-util.h | 3 +- + src/test/test-path-util.c | 66 +-------- + 12 files changed, 62 insertions(+), 242 deletions(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index eedd9b824..4e066613d 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -749,7 +749,7 @@ static int automount_start(Unit *u) { + assert(a); + assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED); + +- if (path_is_mount_point(a->where, 0)) { ++ if (path_is_mount_point(a->where, false)) { + log_unit_error(u->id, + "Path %s is already a mount point, refusing start for %s", + a->where, u->id); +diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c +index 1121d373f..d00a53246 100644 +--- a/src/core/machine-id-setup.c ++++ b/src/core/machine-id-setup.c +@@ -203,7 +203,7 @@ int machine_id_commit(const char *root) { + etc_machine_id = path_kill_slashes(x); + } + +- r = path_is_mount_point(etc_machine_id, 0); ++ r = path_is_mount_point(etc_machine_id, false); + if (r < 0) + return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", etc_machine_id); + if (r == 0) { +diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c +index 2b8fbab1a..521545e5c 100644 +--- a/src/core/mount-setup.c ++++ b/src/core/mount-setup.c +@@ -160,7 +160,7 @@ static int mount_one(const MountPoint *p, bool relabel) { + if (relabel) + label_fix(p->where, true, true); + +- r = path_is_mount_point(p->where, AT_SYMLINK_FOLLOW); ++ r = path_is_mount_point(p->where, true); + if (r < 0) + return r; + +diff --git a/src/efi-boot-generator/efi-boot-generator.c b/src/efi-boot-generator/efi-boot-generator.c +index 5492b1994..b3ff3a8b7 100644 +--- a/src/efi-boot-generator/efi-boot-generator.c ++++ b/src/efi-boot-generator/efi-boot-generator.c +@@ -69,7 +69,7 @@ int main(int argc, char *argv[]) { + return EXIT_SUCCESS; + } + +- if (path_is_mount_point("/boot", AT_SYMLINK_FOLLOW) <= 0 && ++ if (path_is_mount_point("/boot", true) <= 0 && + dir_is_empty("/boot") <= 0) { + log_debug("/boot already populated, exiting."); + return EXIT_SUCCESS; +diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c +index d7b047118..00a2141a5 100644 +--- a/src/gpt-auto-generator/gpt-auto-generator.c ++++ b/src/gpt-auto-generator/gpt-auto-generator.c +@@ -299,7 +299,7 @@ static int probe_and_add_mount( + assert(where); + assert(description); + +- if (path_is_mount_point(where, AT_SYMLINK_FOLLOW) <= 0 && ++ if (path_is_mount_point(where, true) <= 0 && + dir_is_empty(where) <= 0) { + log_debug("%s already populated, ignoring.", where); + return 0; +diff --git a/src/login/logind-user.c b/src/login/logind-user.c +index 912c50ebd..4298704ce 100644 +--- a/src/login/logind-user.c ++++ b/src/login/logind-user.c +@@ -320,7 +320,7 @@ static int user_mkdir_runtime_path(User *u) { + } else + p = u->runtime_path; + +- if (path_is_mount_point(p, 0) <= 0) { ++ if (path_is_mount_point(p, false) <= 0) { + _cleanup_free_ char *t = NULL; + + (void) mkdir(p, 0700); +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index a90a3a5d7..ea365b3f9 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -863,7 +863,7 @@ static int mount_all(const char *dest) { + if (!where) + return log_oom(); + +- t = path_is_mount_point(where, AT_SYMLINK_FOLLOW); ++ t = path_is_mount_point(where, true); + if (t < 0) { + log_error_errno(t, "Failed to detect whether %s is a mount point: %m", where); + +@@ -989,7 +989,7 @@ static int mount_cgroup_hierarchy(const char *dest, const char *controller, cons + + to = strjoina(dest, "/sys/fs/cgroup/", hierarchy); + +- r = path_is_mount_point(to, 0); ++ r = path_is_mount_point(to, false); + if (r < 0) + return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to); + if (r > 0) +@@ -1787,7 +1787,7 @@ static int setup_journal(const char *directory) { + if (!p || !q) + return log_oom(); + +- if (path_is_mount_point(p, 0) > 0) { ++ if (path_is_mount_point(p, false) > 0) { + if (arg_link_journal != LINK_AUTO) { + log_error("%s: already a mount point, refusing to use for journal", p); + return -EEXIST; +@@ -1796,7 +1796,7 @@ static int setup_journal(const char *directory) { + return 0; + } + +- if (path_is_mount_point(q, 0) > 0) { ++ if (path_is_mount_point(q, false) > 0) { + if (arg_link_journal != LINK_AUTO) { + log_error("%s: already a mount point, refusing to use for journal", q); + return -EEXIST; +@@ -3665,7 +3665,7 @@ int main(int argc, char *argv[]) { + * the specified is not a mount point we + * create the new snapshot in the parent + * directory, just next to it. */ +- r = path_is_mount_point(arg_directory, 0); ++ r = path_is_mount_point(arg_directory, false); + if (r < 0) { + log_error_errno(r, "Failed to determine whether directory %s is mount point: %m", arg_directory); + goto finish; +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index cf085cb5f..c5d9e4bb5 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -488,7 +488,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch + if (_unlikely_(!good)) { + int r; + +- r = path_is_mount_point("/sys/fs/cgroup", 0); ++ r = path_is_mount_point("/sys/fs/cgroup", false); + if (r <= 0) + return r < 0 ? r : -ENOENT; + +diff --git a/src/shared/condition.c b/src/shared/condition.c +index 0d2cd2bc3..796cc520d 100644 +--- a/src/shared/condition.c ++++ b/src/shared/condition.c +@@ -350,7 +350,7 @@ static int condition_test_path_is_mount_point(Condition *c) { + assert(c->parameter); + assert(c->type == CONDITION_PATH_IS_MOUNT_POINT); + +- return path_is_mount_point(c->parameter, AT_SYMLINK_FOLLOW) > 0; ++ return path_is_mount_point(c->parameter, true) > 0; + } + + static int condition_test_path_is_read_write(Condition *c) { +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index 0f252ec26..1181ffb9d 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -36,7 +36,6 @@ + #include "strv.h" + #include "path-util.h" + #include "missing.h" +-#include "fileio.h" + + bool path_is_absolute(const char *p) { + return p[0] == '/'; +@@ -474,203 +473,87 @@ char* path_join(const char *root, const char *path, const char *rest) { + NULL); + } + +-static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { +- char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; +- _cleanup_free_ char *fdinfo = NULL; +- _cleanup_close_ int subfd = -1; +- char *p; +- int r; +- +- if ((flags & AT_EMPTY_PATH) && isempty(filename)) +- xsprintf(path, "/proc/self/fdinfo/%i", fd); +- else { +- subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); +- if (subfd < 0) +- return -errno; +- +- xsprintf(path, "/proc/self/fdinfo/%i", subfd); +- } +- +- r = read_full_file(path, &fdinfo, NULL); +- if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ +- return -EOPNOTSUPP; +- if (r < 0) +- return -errno; +- +- p = startswith(fdinfo, "mnt_id:"); +- if (!p) { +- p = strstr(fdinfo, "\nmnt_id:"); +- if (!p) /* The mnt_id field is a relatively new addition */ +- return -EOPNOTSUPP; +- +- p += 8; +- } ++int path_is_mount_point(const char *t, bool allow_symlink) { + +- p += strspn(p, WHITESPACE); +- p[strcspn(p, WHITESPACE)] = 0; +- +- return safe_atoi(p, mnt_id); +-} +- +-int fd_is_mount_point(int fd, const char *filename, int flags) { +- union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; ++ union file_handle_union h = FILE_HANDLE_INIT; + int mount_id = -1, mount_id_parent = -1; +- bool nosupp = false, check_st_dev = true; ++ _cleanup_free_ char *parent = NULL; + struct stat a, b; + int r; ++ bool nosupp = false; + +- assert(fd >= 0); +- assert(filename); ++ /* We are not actually interested in the file handles, but ++ * name_to_handle_at() also passes us the mount ID, hence use ++ * it but throw the handle away */ + +- /* First we will try the name_to_handle_at() syscall, which +- * tells us the mount id and an opaque file "handle". It is +- * not supported everywhere though (kernel compile-time +- * option, not all file systems are hooked up). If it works +- * the mount id is usually good enough to tell us whether +- * something is a mount point. +- * +- * If that didn't work we will try to read the mount id from +- * /proc/self/fdinfo/. This is almost as good as +- * name_to_handle_at(), however, does not return the +- * opaque file handle. The opaque file handle is pretty useful +- * to detect the root directory, which we should always +- * consider a mount point. Hence we use this only as +- * fallback. Exporting the mnt_id in fdinfo is a pretty recent +- * kernel addition. +- * +- * As last fallback we do traditional fstat() based st_dev +- * comparisons. This is how things were traditionally done, +- * but unionfs breaks breaks this since it exposes file +- * systems with a variety of st_dev reported. Also, btrfs +- * subvolumes have different st_dev, even though they aren't +- * real mounts of their own. */ +- +- r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); ++ if (path_equal(t, "/")) ++ return 1; ++ ++ r = name_to_handle_at(AT_FDCWD, t, &h.handle, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0); + if (r < 0) { + if (errno == ENOSYS) + /* This kernel does not support name_to_handle_at() +- * fall back to simpler logic. */ +- goto fallback_fdinfo; ++ * fall back to the traditional stat() logic. */ ++ goto fallback; + else if (errno == EOPNOTSUPP) + /* This kernel or file system does not support +- * name_to_handle_at(), hence let's see if the +- * upper fs supports it (in which case it is a +- * mount point), otherwise fallback to the ++ * name_to_handle_at(), hence fallback to the + * traditional stat() logic */ + nosupp = true; ++ else if (errno == ENOENT) ++ return 0; + else + return -errno; + } + +- r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); +- if (r < 0) { +- if (errno == EOPNOTSUPP) { ++ r = path_get_parent(t, &parent); ++ if (r < 0) ++ return r; ++ ++ h.handle.handle_bytes = MAX_HANDLE_SZ; ++ r = name_to_handle_at(AT_FDCWD, parent, &h.handle, &mount_id_parent, AT_SYMLINK_FOLLOW); ++ if (r < 0) ++ if (errno == EOPNOTSUPP) + if (nosupp) + /* Neither parent nor child do name_to_handle_at()? + We have no choice but to fall back. */ +- goto fallback_fdinfo; ++ goto fallback; + else +- /* The parent can't do name_to_handle_at() but the +- * directory we are interested in can? ++ /* The parent can't do name_to_handle_at() but ++ * the directory we are interested in can? ++ * Or the other way around? + * If so, it must be a mount point. */ + return 1; +- } else ++ else + return -errno; +- } ++ else ++ return mount_id != mount_id_parent; + +- /* The parent can do name_to_handle_at() but the +- * directory we are interested in can't? If so, it +- * must be a mount point. */ +- if (nosupp) +- return 1; ++fallback: ++ if (allow_symlink) ++ r = stat(t, &a); ++ else ++ r = lstat(t, &a); + +- /* If the file handle for the directory we are +- * interested in and its parent are identical, we +- * assume this is the root directory, which is a mount +- * point. */ ++ if (r < 0) { ++ if (errno == ENOENT) ++ return 0; + +- if (h.handle.handle_bytes == h_parent.handle.handle_bytes && +- h.handle.handle_type == h_parent.handle.handle_type && +- memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) +- return 1; ++ return -errno; ++ } + +- return mount_id != mount_id_parent; ++ free(parent); ++ parent = NULL; + +-fallback_fdinfo: +- r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); +- if (r == -EOPNOTSUPP) +- goto fallback_fstat; ++ r = path_get_parent(t, &parent); + if (r < 0) + return r; + +- r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); ++ r = stat(parent, &b); + if (r < 0) +- return r; +- +- if (mount_id != mount_id_parent) +- return 1; +- +- /* Hmm, so, the mount ids are the same. This leaves one +- * special case though for the root file system. For that, +- * let's see if the parent directory has the same inode as we +- * are interested in. Hence, let's also do fstat() checks now, +- * too, but avoid the st_dev comparisons, since they aren't +- * that useful on unionfs mounts. */ +- check_st_dev = false; +- +-fallback_fstat: +- /* yay for fstatat() taking a different set of flags than the other +- * _at() above */ +- if (flags & AT_SYMLINK_FOLLOW) +- flags &= ~AT_SYMLINK_FOLLOW; +- else +- flags |= AT_SYMLINK_NOFOLLOW; +- if (fstatat(fd, filename, &a, flags) < 0) +- return -errno; +- +- if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) +- return -errno; +- +- /* A directory with same device and inode as its parent? Must +- * be the root directory */ +- if (a.st_dev == b.st_dev && +- a.st_ino == b.st_ino) +- return 1; +- +- return check_st_dev && (a.st_dev != b.st_dev); +-} +- +-/* flags can be AT_SYMLINK_FOLLOW or 0 */ +-int path_is_mount_point(const char *t, int flags) { +- _cleanup_close_ int fd = -1; +- _cleanup_free_ char *canonical = NULL, *parent = NULL; +- +- assert(t); +- +- if (path_equal(t, "/")) +- return 1; +- +- /* we need to resolve symlinks manually, we can't just rely on +- * fd_is_mount_point() to do that for us; if we have a structure like +- * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we +- * look at needs to be /usr, not /. */ +- if (flags & AT_SYMLINK_FOLLOW) { +- canonical = canonicalize_file_name(t); +- if (!canonical) +- return -errno; +- +- t = canonical; +- } +- +- parent = dirname_malloc(t); +- if (!parent) +- return -ENOMEM; +- +- fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); +- if (fd < 0) + return -errno; + +- return fd_is_mount_point(fd, basename(t), flags); ++ return a.st_dev != b.st_dev; + } + + int path_is_read_only_fs(const char *path) { +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index e16484087..71bb740e9 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -53,8 +53,7 @@ char** path_strv_make_absolute_cwd(char **l); + char** path_strv_resolve(char **l, const char *prefix); + char** path_strv_resolve_uniq(char **l, const char *prefix); + +-int fd_is_mount_point(int fd, const char *filename, int flags); +-int path_is_mount_point(const char *path, int flags); ++int path_is_mount_point(const char *path, bool allow_symlink); + int path_is_read_only_fs(const char *path); + int path_is_os_tree(const char *path); + +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index 8870f178a..6396fcb39 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -21,7 +21,6 @@ + + #include + #include +-#include + + #include "path-util.h" + #include "util.h" +@@ -86,8 +85,8 @@ static void test_path(void) { + test_parent("/aa///file...", "/aa///"); + test_parent("file.../", NULL); + +- assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW)); +- assert_se(path_is_mount_point("/", 0)); ++ assert_se(path_is_mount_point("/", true)); ++ assert_se(path_is_mount_point("/", false)); + + { + char p1[] = "aaa/bbb////ccc"; +@@ -100,66 +99,6 @@ static void test_path(void) { + } + } + +-static void test_path_is_mount_point(void) { +- int fd, rt, rf, rlt, rlf; +- char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX"; +- _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL; +- +- assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW) > 0); +- assert_se(path_is_mount_point("/", 0) > 0); +- +- assert_se(path_is_mount_point("/proc", AT_SYMLINK_FOLLOW) > 0); +- assert_se(path_is_mount_point("/proc", 0) > 0); +- +- assert_se(path_is_mount_point("/proc/1", AT_SYMLINK_FOLLOW) == 0); +- assert_se(path_is_mount_point("/proc/1", 0) == 0); +- +- assert_se(path_is_mount_point("/sys", AT_SYMLINK_FOLLOW) > 0); +- assert_se(path_is_mount_point("/sys", 0) > 0); +- +- /* file mountpoints */ +- assert_se(mkdtemp(tmp_dir) != NULL); +- file1 = path_join(NULL, tmp_dir, "file1"); +- assert_se(file1); +- file2 = path_join(NULL, tmp_dir, "file2"); +- assert_se(file2); +- fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); +- assert_se(fd > 0); +- close(fd); +- fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); +- assert_se(fd > 0); +- close(fd); +- link1 = path_join(NULL, tmp_dir, "link1"); +- assert_se(link1); +- assert_se(symlink("file1", link1) == 0); +- link2 = path_join(NULL, tmp_dir, "link2"); +- assert_se(link1); +- assert_se(symlink("file2", link2) == 0); +- +- assert_se(path_is_mount_point(file1, AT_SYMLINK_FOLLOW) == 0); +- assert_se(path_is_mount_point(file1, 0) == 0); +- assert_se(path_is_mount_point(link1, AT_SYMLINK_FOLLOW) == 0); +- assert_se(path_is_mount_point(link1, 0) == 0); +- +- /* this test will only work as root */ +- if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) { +- rf = path_is_mount_point(file2, 0); +- rt = path_is_mount_point(file2, AT_SYMLINK_FOLLOW); +- rlf = path_is_mount_point(link2, 0); +- rlt = path_is_mount_point(link2, AT_SYMLINK_FOLLOW); +- +- assert_se(umount(file2) == 0); +- +- assert_se(rf == 1); +- assert_se(rt == 1); +- assert_se(rlf == 0); +- assert_se(rlt == 1); +- } else +- printf("Skipping bind mount file test: %m\n"); +- +- assert_se(rm_rf(tmp_dir, false, true, false) == 0); +-} +- + static void test_find_binary(const char *self, bool local) { + char *p; + +@@ -349,7 +288,6 @@ int main(int argc, char **argv) { + test_make_relative(); + test_strv_resolve(); + test_path_startswith(); +- test_path_is_mount_point(); + + return 0; + } diff --git a/SOURCES/0530-device-make-sure-to-remove-all-device-units-sharing-.patch b/SOURCES/0530-device-make-sure-to-remove-all-device-units-sharing-.patch new file mode 100644 index 0000000..fddfd6b --- /dev/null +++ b/SOURCES/0530-device-make-sure-to-remove-all-device-units-sharing-.patch @@ -0,0 +1,43 @@ +From 562bccced876d3bc0e9521ef31f6cc1e5cff9798 Mon Sep 17 00:00:00 2001 +From: Franck Bui +Date: Wed, 30 Aug 2017 17:16:16 +0200 +Subject: [PATCH] device: make sure to remove all device units sharing the same + sysfs path (#6679) + +When a device is unplugged all device units sharing the same sysfs path +pointing to that device are supposed to be removed. + +However it didn't work since while iterating the device unit list containing +all the relevant units, each unit was removed during each iteration of +LIST_FOREACH. However LIST_FOREACH doesn't support this use case and +LIST_FOREACH_SAFE must be use instead. + +(cherry picked from commit cc0df6cc35339976c367977dc292278a1939db0c) + +Related: #1408916 +--- + src/core/device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/core/device.c b/src/core/device.c +index 63a04bdd3..2afa19f2b 100644 +--- a/src/core/device.c ++++ b/src/core/device.c +@@ -487,7 +487,7 @@ static void device_update_found_one(Device *d, bool add, DeviceFound found, bool + } + + static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) { +- Device *d, *l; ++ Device *d, *l, *n; + + assert(m); + assert(sysfs); +@@ -496,7 +496,7 @@ static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, + return 0; + + l = hashmap_get(m->devices_by_sysfs, sysfs); +- LIST_FOREACH(same_sysfs, d, l) ++ LIST_FOREACH_SAFE(same_sysfs, d, n, l) + device_update_found_one(d, add, found, now); + + return 0; diff --git a/SOURCES/0531-manager-when-reexecuting-try-to-connect-to-bus-only-.patch b/SOURCES/0531-manager-when-reexecuting-try-to-connect-to-bus-only-.patch new file mode 100644 index 0000000..bd82b93 --- /dev/null +++ b/SOURCES/0531-manager-when-reexecuting-try-to-connect-to-bus-only-.patch @@ -0,0 +1,48 @@ +From 8410dde8d9593c1d96593b17d610d7daf955dab3 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 8 Sep 2017 15:41:44 +0200 +Subject: [PATCH] manager: when reexecuting try to connect to bus only when + dbus.service is around (#6773) + +Trying to connect otherwise is pointless, because if socket isn't around +we won't connect. However, when dbus.socket is present we attempt to +connect. That attempt can't succeed because we are then supposed +to activate dbus.service as a response to connection from +us. This results in deadlock. + +Fixes #6303 + +(cherry picked from commit 5463fa0a88f95d2002858592578f9bf4e0d2660a) + +Resolves: #1465737 +--- + src/core/manager.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 287cf6a74..041fac46b 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -799,16 +799,19 @@ static int manager_setup_kdbus(Manager *m) { + + static int manager_connect_bus(Manager *m, bool reexecuting) { + bool try_bus_connect; ++ Unit *u = NULL; + + assert(m); + + if (m->test_run) + return 0; + ++ u = manager_get_unit(m, SPECIAL_DBUS_SERVICE); ++ + try_bus_connect = +- m->kdbus_fd >= 0 || +- reexecuting || +- (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS")); ++ (u && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) && ++ (reexecuting || ++ (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"))); + + /* Try to connect to the busses, if possible. */ + return bus_init(m, try_bus_connect); diff --git a/SOURCES/0532-doc-document-service-exit-codes.patch b/SOURCES/0532-doc-document-service-exit-codes.patch new file mode 100644 index 0000000..7fcdd5c --- /dev/null +++ b/SOURCES/0532-doc-document-service-exit-codes.patch @@ -0,0 +1,337 @@ +From a2176ebec2b1ff05b599362af2f8426e1c4fd3ef Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 26 Jan 2017 13:45:46 +0100 +Subject: [PATCH] doc: document service exit codes + +(Heavily reworked by Lennart while rebasing) + +Fixes: #3545 +Replaces: #5159 +(cherry picked from commit 91a8f867b6fcdb9b2c4074b571e992e6c7869428) + +Resolves: #1178929 +--- + man/systemd.exec.xml | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 310 insertions(+) + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 1b14ced78..508146f06 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -1360,6 +1360,316 @@ + cf. pam_env8. + + ++ ++ Process exit codes ++ ++ When invoking a unit process the service manager possibly fails to apply the execution parameters configured ++ with the settings above. In that case the already created service process will exit with a non-zero exit code ++ before the configured command line is executed. (Or in other words, the child process possibly exits with these ++ error codes, after having been created by the fork2 system call, but ++ before the matching execve2 system call is ++ called.) Specifically, exit codes defined by the C library, by the LSB specification and by the systemd service ++ manager itself are used. ++ ++ The following basic service exit codes are defined by the C library. ++ ++ ++ Basic C library exit codes ++ ++ ++ ++ Exit Code ++ Symbolic Name ++ Description ++ ++ ++ ++ ++ 0 ++ EXIT_SUCCESS ++ Generic success code. ++ ++ ++ 1 ++ EXIT_FAILURE ++ Generic failure or unspecified error. ++ ++ ++ ++
++ ++ The following service exit codes are defined by the LSB specification ++ . ++ ++ ++ ++ LSB service exit codes ++ ++ ++ ++ Exit Code ++ Symbolic Name ++ Description ++ ++ ++ ++ ++ 2 ++ EXIT_INVALIDARGUMENT ++ Invalid or excess arguments. ++ ++ ++ 3 ++ EXIT_NOTIMPLEMENTED ++ Unimplemented feature. ++ ++ ++ 4 ++ EXIT_NOPERMISSION ++ The user has insufficient privileges. ++ ++ ++ 5 ++ EXIT_NOTINSTALLED ++ The program is not installed. ++ ++ ++ 6 ++ EXIT_NOTCONFIGURED ++ The program is not configured. ++ ++ ++ 7 ++ EXIT_NOTRUNNING ++ The program is not running. ++ ++ ++ ++
++ ++ ++ The LSB specification suggests that error codes 200 and above are reserved for implementations. Some of them are ++ used by the service manager to indicate problems during process invocation: ++ ++ ++ systemd-specific exit codes ++ ++ ++ ++ Exit Code ++ Symbolic Name ++ Description ++ ++ ++ ++ ++ 200 ++ EXIT_CHDIR ++ Changing to the requested working directory failed. See WorkingDirectory= above. ++ ++ ++ 201 ++ EXIT_NICE ++ Failed to set up process scheduling priority (nice level). See Nice= above. ++ ++ ++ 202 ++ EXIT_FDS ++ Failed to close unwanted file descriptors, or to adjust passed file descriptors. ++ ++ ++ 203 ++ EXIT_EXEC ++ The actual process execution failed (specifically, the execve2 system call). Most likely this is caused by a missing or non-accessible executable file. ++ ++ ++ 204 ++ EXIT_MEMORY ++ Failed to perform an action due to memory shortage. ++ ++ ++ 205 ++ EXIT_LIMITS ++ Failed to adjust resoure limits. See LimitCPU= and related settings above. ++ ++ ++ 206 ++ EXIT_OOM_ADJUST ++ Failed to adjust the OOM setting. See OOMScoreAdjust= above. ++ ++ ++ 207 ++ EXIT_SIGNAL_MASK ++ Failed to set process signal mask. ++ ++ ++ 208 ++ EXIT_STDIN ++ Failed to set up standard input. See StandardInput= above. ++ ++ ++ 209 ++ EXIT_STDOUT ++ Failed to set up standard output. See StandardOutput= above. ++ ++ ++ 210 ++ EXIT_CHROOT ++ Failed to change root directory (chroot2). See RootDirectory=/RootImage= above. ++ ++ ++ 211 ++ EXIT_IOPRIO ++ Failed to set up IO scheduling priority. See IOSchedulingClass=/IOSchedulingPriority= above. ++ ++ ++ 212 ++ EXIT_TIMERSLACK ++ Failed to set up timer slack. See TimerSlackNSec= above. ++ ++ ++ 213 ++ EXIT_SECUREBITS ++ Failed to set process secure bits. See SecureBits= above. ++ ++ ++ 214 ++ EXIT_SETSCHEDULER ++ Failed to set up CPU scheduling. See CPUSchedulingPolicy=/CPUSchedulingPriority= above. ++ ++ ++ 215 ++ EXIT_CPUAFFINITY ++ Failed to set up CPU affinity. See CPUAffinity= above. ++ ++ ++ 216 ++ EXIT_GROUP ++ Failed to determine or change group credentials. See Group=/SupplementaryGroups= above. ++ ++ ++ 217 ++ EXIT_USER ++ Failed to determine or change user credentials, or to set up user namespacing. See User=/PrivateUsers= above. ++ ++ ++ 218 ++ EXIT_CAPABILITIES ++ Failed to drop capabilities, or apply ambient capabilities. See CapabilityBoundingSet=/AmbientCapabilities= above. ++ ++ ++ 219 ++ EXIT_CGROUP ++ Setting up the service control group failed. ++ ++ ++ 220 ++ EXIT_SETSID ++ Failed to create new process session. ++ ++ ++ 221 ++ EXIT_CONFIRM ++ Execution has been cancelled by the user. See the systemd.confirm_spawn= kernel command line setting on kernel-command-line7 for details. ++ ++ ++ 222 ++ EXIT_STDERR ++ Failed to set up standard error output. See StandardError= above. ++ ++ ++ 224 ++ EXIT_PAM ++ Failed to set up PAM session. See PAMName= above. ++ ++ ++ 225 ++ EXIT_NETWORK ++ Failed to set up network namespacing. See PrivateNetwork= above. ++ ++ ++ 226 ++ EXIT_NAMESPACE ++ Failed to set up mount namespacing. See ReadOnlyPaths= and related settings above. ++ ++ ++ 227 ++ EXIT_NO_NEW_PRIVILEGES ++ Failed to disable new priviliges. See NoNewPrivileges=yes above. ++ ++ ++ 228 ++ EXIT_SECCOMP ++ Failed to apply system call filters. See SystemCallFilter= and related settings above. ++ ++ ++ 229 ++ EXIT_SELINUX_CONTEXT ++ Determining or changing SELinux context failed. See SELinuxContext= above. ++ ++ ++ 230 ++ EXIT_PERSONALITY ++ Failed to set up a execution domain (personality). See Personality= above. ++ ++ ++ 231 ++ EXIT_APPARMOR_PROFILE ++ Failed to prepare changing AppArmor profile. See AppArmorProfile= above. ++ ++ ++ 232 ++ EXIT_ADDRESS_FAMILIES ++ Failed to restrict address families. See RestrictAddressFamilies= above. ++ ++ ++ 233 ++ EXIT_RUNTIME_DIRECTORY ++ Setting up runtime directory failed. See RuntimeDirectory= and related settings above. ++ ++ ++ 235 ++ EXIT_CHOWN ++ Failed to adjust socket ownership. Used for socket units only. ++ ++ ++ 236 ++ EXIT_SMACK_PROCESS_LABEL ++ Failed to set SMACK label. See SmackProcessLabel= above. ++ ++ ++ 237 ++ EXIT_KEYRING ++ Failed to set up kernel keyring. ++ ++ ++ 238 ++ EXIT_STATE_DIRECTORY ++ Failed to set up a the unit's state directory. See StateDirectory= above. ++ ++ ++ 239 ++ EXIT_CACHE_DIRECTORY ++ Failed to set up a the unit's cache directory. See CacheDirectory= above. ++ ++ ++ 240 ++ EXIT_LOGS_DIRECTORY ++ Failed to set up a the unit's logging directory. See LogsDirectory= above. ++ ++ ++ 241 ++ EXIT_CONFIGURATION_DIRECTORY ++ Failed to set up a the unit's configuration directory. See ConfigurationDirectory= above. ++ ++ ++ ++
++
++ + + See Also + diff --git a/SOURCES/0533-units-order-cryptsetup-pre.target-before-cryptsetup..patch b/SOURCES/0533-units-order-cryptsetup-pre.target-before-cryptsetup..patch new file mode 100644 index 0000000..ba9d7a6 --- /dev/null +++ b/SOURCES/0533-units-order-cryptsetup-pre.target-before-cryptsetup..patch @@ -0,0 +1,25 @@ +From acf59b657e23e3b5b0f038823fe57dcfb4f914a4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 5 Sep 2017 09:14:51 +0200 +Subject: [PATCH] units: order cryptsetup-pre.target before cryptsetup.target + +Normally this happens automatically, but if it happened that both targets were +pulled in, even though there were no cryptsetup units, they could be started +in reverse order, which would be somewhat confusing. Add an explicit ordering +to avoid this potential issue. + +Cherry-picked from: 947d21171bdd8375db6482bc7d758d74b27f7dd4 +Resolves: #1384014 +--- + units/cryptsetup-pre.target | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/units/cryptsetup-pre.target b/units/cryptsetup-pre.target +index 65353419f..42e35dd4e 100644 +--- a/units/cryptsetup-pre.target ++++ b/units/cryptsetup-pre.target +@@ -9,3 +9,4 @@ + Description=Encrypted Volumes (Pre) + Documentation=man:systemd.special(7) + RefuseManualStart=yes ++Before=cryptsetup.target diff --git a/SOURCES/0534-man-add-an-explicit-description-of-_netdev-to-system.patch b/SOURCES/0534-man-add-an-explicit-description-of-_netdev-to-system.patch new file mode 100644 index 0000000..0709d77 --- /dev/null +++ b/SOURCES/0534-man-add-an-explicit-description-of-_netdev-to-system.patch @@ -0,0 +1,41 @@ +From eb628c9f0ec9dcaec41dadc7ff594c8420b78a71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 5 Sep 2017 11:20:14 +0200 +Subject: [PATCH] man: add an explicit description of _netdev to + systemd.mount(5) + +It was mentioned in passing, but having it in the list of options is also +nice. + +Cherry-picked from: 0f00528db4e941503ec8cb5052367b17a8b566ba +Resolves: #1384014 +--- + man/systemd.mount.xml | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml +index 04ed1e1cf..dfa437b5d 100644 +--- a/man/systemd.mount.xml ++++ b/man/systemd.mount.xml +@@ -202,6 +202,21 @@ + setting in a unit file. + +
++ ++ ++ ++ Normally the file system type is used to determine if a ++ mount is a "network mount", i.e. if it should only be started after the ++ network is available. Using this option overrides this detection and ++ specifies that the mount requires network. ++ ++ Network mount units are ordered between remote-fs-pre.target ++ and remote-fs.target, instead of ++ local-fs-pre.target and local-fs.target. ++ They also pull in network-online.target and are ordered after ++ it and network.target. ++ ++ + + + diff --git a/SOURCES/0535-units-add-remote-cryptsetup.target-and-remote-crypts.patch b/SOURCES/0535-units-add-remote-cryptsetup.target-and-remote-crypts.patch new file mode 100644 index 0000000..3c3e8b8 --- /dev/null +++ b/SOURCES/0535-units-add-remote-cryptsetup.target-and-remote-crypts.patch @@ -0,0 +1,140 @@ +From ea1a15b35b70573ab61ca0b8123205c6885c69e4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 5 Sep 2017 10:15:13 +0200 +Subject: [PATCH] units: add remote-cryptsetup.target and + remote-cryptsetup-pre.target + +The pair is similar to remote-fs.target and remote-fs-pre.target. Any +cryptsetup devices which require network shall be ordered after +remote-cryptsetup-pre.target and before remote-cryptsetup.target. + +Cherry-picked from: 889128b8b27abb13e1691a72e4ce0562c564e257 +Resolves: #1384014 +--- + Makefile.am | 4 +++- + man/systemd.special.xml | 23 +++++++++++++++++++++++ + units/cryptsetup-pre.target | 2 +- + units/cryptsetup.target | 2 +- + units/remote-cryptsetup-pre.target | 15 +++++++++++++++ + units/remote-cryptsetup.target | 10 ++++++++++ + 6 files changed, 53 insertions(+), 3 deletions(-) + create mode 100644 units/remote-cryptsetup-pre.target + create mode 100644 units/remote-cryptsetup.target + +diff --git a/Makefile.am b/Makefile.am +index 0e2f8d561..a1ebf5cb0 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4861,7 +4861,9 @@ systemgenerator_PROGRAMS += \ + + dist_systemunit_DATA += \ + units/cryptsetup.target \ +- units/cryptsetup-pre.target ++ units/cryptsetup-pre.target \ ++ units/remote-cryptsetup.target \ ++ units/remote-cryptsetup-pre.target + + systemd_cryptsetup_SOURCES = \ + src/cryptsetup/cryptsetup.c +diff --git a/man/systemd.special.xml b/man/systemd.special.xml +index eb464f9f8..5529d3bf7 100644 +--- a/man/systemd.special.xml ++++ b/man/systemd.special.xml +@@ -81,6 +81,8 @@ + poweroff.target, + printer.target, + reboot.target, ++ remote-cryptsetup-pre.target, ++ remote-cryptsetup.target, + remote-fs.target, + remote-fs-pre.target, + rescue.target, +@@ -404,6 +406,27 @@ + this target unit, for compatibility with SysV. + + ++ ++ remote-cryptsetup-pre.target ++ ++ This target unit is automatically ordered before all cryptsetup devices ++ marked with the . It can be used to execute additional ++ units before such devices are set up. ++ ++ It is ordered after network.target and ++ network-online.target, and also pulls the latter in as a ++ Wants= dependency. ++ ++ ++ ++ remote-cryptsetup.target ++ ++ Similar to cryptsetup.target, but for encrypted ++ devices which are accessed over the network. It is used for ++ crypttab8 ++ entries marked with . ++ ++ + + remote-fs.target + +diff --git a/units/cryptsetup-pre.target b/units/cryptsetup-pre.target +index 42e35dd4e..6cb28a61a 100644 +--- a/units/cryptsetup-pre.target ++++ b/units/cryptsetup-pre.target +@@ -6,7 +6,7 @@ + # (at your option) any later version. + + [Unit] +-Description=Encrypted Volumes (Pre) ++Description=Local Encrypted Volumes (Pre) + Documentation=man:systemd.special(7) + RefuseManualStart=yes + Before=cryptsetup.target +diff --git a/units/cryptsetup.target b/units/cryptsetup.target +index 25d3e33f6..10b17fd38 100644 +--- a/units/cryptsetup.target ++++ b/units/cryptsetup.target +@@ -6,5 +6,5 @@ + # (at your option) any later version. + + [Unit] +-Description=Encrypted Volumes ++Description=Local Encrypted Volumes + Documentation=man:systemd.special(7) +diff --git a/units/remote-cryptsetup-pre.target b/units/remote-cryptsetup-pre.target +new file mode 100644 +index 000000000..a375e6188 +--- /dev/null ++++ b/units/remote-cryptsetup-pre.target +@@ -0,0 +1,15 @@ ++# This file is part of systemd. ++# ++# systemd is free software; you can redistribute it and/or modify it ++# under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++ ++[Unit] ++Description=Remote Encrypted Volumes (Pre) ++Documentation=man:systemd.special(7) ++RefuseManualStart=yes ++Before=remote-cryptsetup.target ++ ++After=network.target network-online.target ++Wants=network-online.target +diff --git a/units/remote-cryptsetup.target b/units/remote-cryptsetup.target +new file mode 100644 +index 000000000..60943bd1c +--- /dev/null ++++ b/units/remote-cryptsetup.target +@@ -0,0 +1,10 @@ ++# This file is part of systemd. ++# ++# systemd is free software; you can redistribute it and/or modify it ++# under the terms of the GNU Lesser General Public License as published by ++# the Free Software Foundation; either version 2.1 of the License, or ++# (at your option) any later version. ++ ++[Unit] ++Description=Remote Encrypted Volumes ++Documentation=man:systemd.special(7) diff --git a/SOURCES/0536-cryptsetup-generator-use-remote-cryptsetup.target-wh.patch b/SOURCES/0536-cryptsetup-generator-use-remote-cryptsetup.target-wh.patch new file mode 100644 index 0000000..2b8fccc --- /dev/null +++ b/SOURCES/0536-cryptsetup-generator-use-remote-cryptsetup.target-wh.patch @@ -0,0 +1,125 @@ +From d09c35c48005669c4c4663e3ba8a6f979432cead Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Tue, 5 Sep 2017 11:30:33 +0200 +Subject: [PATCH] cryptsetup-generator: use remote-cryptsetup.target when + _netdev is present + +This allows such devices to depend on the network. Their startup will +be delayed similarly to network mount units. + +Fixes #4642. + +Cherry-picked from: b001ad61e91b6499897f0c977045c7608c233bfa +Resolves: #1384014 +--- + man/crypttab.xml | 13 +++++++++++++ + src/cryptsetup/cryptsetup-generator.c | 36 +++++++++++++++++++++++------------ + 2 files changed, 37 insertions(+), 12 deletions(-) + +diff --git a/man/crypttab.xml b/man/crypttab.xml +index 3e249ad23..7085a1623 100644 +--- a/man/crypttab.xml ++++ b/man/crypttab.xml +@@ -189,6 +189,19 @@ + . + + ++ ++ ++ ++ Marks this cryptsetup device as requiring network. It will be ++ started after the network is available, similarly to ++ systemd.mount5 ++ units marked with . The service unit to set up this device ++ will be ordered between remote-cryptsetup-pre.target and ++ remote-cryptsetup.target, instead of ++ cryptsetup-pre.target and ++ cryptsetup.target. ++ ++ + + + +diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c +index d191def5f..49dc8f14b 100644 +--- a/src/cryptsetup/cryptsetup-generator.c ++++ b/src/cryptsetup/cryptsetup-generator.c +@@ -60,7 +60,7 @@ static int create_disk( + _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *to = NULL, *e = NULL, + *filtered = NULL; + _cleanup_fclose_ FILE *f = NULL; +- bool noauto, nofail, tmp, swap; ++ bool noauto, nofail, tmp, swap, netdev; + char *from; + int r; + +@@ -71,6 +71,7 @@ static int create_disk( + nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0"); + tmp = fstab_test_option(options, "tmp\0"); + swap = fstab_test_option(options, "swap\0"); ++ netdev = fstab_test_option(options, "_netdev\0"); + + if (tmp && swap) { + log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name); +@@ -101,22 +102,24 @@ static int create_disk( + if (!f) + return log_error_errno(errno, "Failed to create unit file %s: %m", p); + +- fputs( ++ fprintf(f, + "# Automatically generated by systemd-cryptsetup-generator\n\n" + "[Unit]\n" +- "Description=Cryptography Setup for %I\n" ++ "Description=Cryptography Setup for %%I\n" + "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n" + "SourcePath=/etc/crypttab\n" + "DefaultDependencies=no\n" + "Conflicts=umount.target\n" +- "BindsTo=dev-mapper-%i.device\n" ++ "BindsTo=dev-mapper-%%i.device\n" + "IgnoreOnIsolate=true\n" +- "After=systemd-readahead-collect.service systemd-readahead-replay.service cryptsetup-pre.target\n", +- f); ++ "After=systemd-readahead-collect.service systemd-readahead-replay.service\n" ++ "After=%s\n", ++ netdev ? "remote-cryptsetup-pre.target" : "cryptsetup-pre.target"); + + if (!nofail) + fprintf(f, +- "Before=cryptsetup.target\n"); ++ "Before=%s\n", ++ netdev ? "remote-cryptsetup.target" : "cryptsetup.target"); + + if (password) { + if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random")) +@@ -196,16 +199,25 @@ static int create_disk( + return log_error_errno(errno, "Failed to create symlink %s: %m", to); + + free(to); +- if (!nofail) +- to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL); +- else +- to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL); ++ if (!netdev) { ++ if (!nofail) ++ to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL); ++ else ++ to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL); ++ } else { ++ if (!nofail) ++ to = strjoin(arg_dest, "/remote-cryptsetup.target.requires/", n, NULL); ++ else ++ to = strjoin(arg_dest, "/remote-cryptsetup.target.wants/", n, NULL); ++ } + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); +- if (symlink(from, to) < 0) ++ if (symlink(from, to) < 0) { ++ free(to); + return log_error_errno(errno, "Failed to create symlink %s: %m", to); ++ } + } + + free(to); diff --git a/SOURCES/0537-Support-rdma-as-a-ListenNetlink-argument-6626.patch b/SOURCES/0537-Support-rdma-as-a-ListenNetlink-argument-6626.patch new file mode 100644 index 0000000..ebae836 --- /dev/null +++ b/SOURCES/0537-Support-rdma-as-a-ListenNetlink-argument-6626.patch @@ -0,0 +1,28 @@ +From db66a909c0e4ca5d05a0dfa84734c1760ae41e3b Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 25 Sep 2017 10:44:19 +0200 +Subject: [PATCH] Support 'rdma' as a ListenNetlink= argument (#6626) + +NETLINK_RDMA has been in the kernel since v3.0. + +(cherry-picked from commit 5570d7f9561294271591881cf9a249d574069c30) + +Resolves: #1494610 +--- + src/shared/socket-util.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index 79d1582d4..baab6353e 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -725,7 +725,8 @@ static const char* const netlink_family_table[] = { + [NETLINK_KOBJECT_UEVENT] = "kobject-uevent", + [NETLINK_GENERIC] = "generic", + [NETLINK_SCSITRANSPORT] = "scsitransport", +- [NETLINK_ECRYPTFS] = "ecryptfs" ++ [NETLINK_ECRYPTFS] = "ecryptfs", ++ [NETLINK_RDMA] = "rdma", + }; + + DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX); diff --git a/SOURCES/0538-core-namespace-Protect-usr-instead-of-home-with-Prot.patch b/SOURCES/0538-core-namespace-Protect-usr-instead-of-home-with-Prot.patch new file mode 100644 index 0000000..de5b807 --- /dev/null +++ b/SOURCES/0538-core-namespace-Protect-usr-instead-of-home-with-Prot.patch @@ -0,0 +1,29 @@ +From 38d653dbd39cd1e3370e49c5cc7b031a93532e10 Mon Sep 17 00:00:00 2001 +From: Jason Pleau +Date: Sun, 31 May 2015 12:51:17 -0400 +Subject: [PATCH] core/namespace: Protect /usr instead of /home with + ProtectSystem=yes + +A small typo in ee818b8 caused /home to be put in read-only instead of +/usr when ProtectSystem was enabled (ie: not set to "no"). + +(cherry picked from commit d38e01dc96c5cae1986561c4f3bc7f760560bf2a) + +Resolves: #1493047 +--- + src/core/namespace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/namespace.c b/src/core/namespace.c +index 574746273..217dd36cb 100644 +--- a/src/core/namespace.c ++++ b/src/core/namespace.c +@@ -521,7 +521,7 @@ int setup_namespace( + if (protect_system != PROTECT_SYSTEM_NO) { + const char *usr_dir, *boot_dir, *etc_dir; + +- usr_dir = prefix_roota(root_directory, "/home"); ++ usr_dir = prefix_roota(root_directory, "/usr"); + boot_dir = prefix_roota(root_directory, "/boot"); + boot_dir = strjoina("-", boot_dir); + etc_dir = prefix_roota(root_directory, "/etc"); diff --git a/SOURCES/0539-udev-Use-parent-bus-id-for-virtio-disk-builtin-path-.patch b/SOURCES/0539-udev-Use-parent-bus-id-for-virtio-disk-builtin-path-.patch new file mode 100644 index 0000000..3edfc86 --- /dev/null +++ b/SOURCES/0539-udev-Use-parent-bus-id-for-virtio-disk-builtin-path-.patch @@ -0,0 +1,68 @@ +From 104d13b765fac0308dbd01a1f3a0221504bd0412 Mon Sep 17 00:00:00 2001 +From: Viktor Mihajlovski +Date: Wed, 1 Mar 2017 21:30:17 +0100 +Subject: [PATCH] udev: Use parent bus id for virtio disk builtin path-id + (#5500) + +The builtin path id for virtio block devices has been changed +to use the bus id without a prefix "virtio-pci" to be +compatible with all virtio transport types. + +In order to not break existing setups, the by-path symlinks for +virtio block devices on the PCI bus are reintroduced by udev rules. +The virtio-pci symlinks are considered to be deprecated and +should be replaced by the native PCI symlinks. + +Example output for a virtio disk in PCI slot 7: + $ ls /dev/disk/by-path + pci-0000:00:07.0 + pci-0000:00:07.0-part1 + virtio-pci-0000:00:07.0 + virtio-pci-0000:00:07.0-part1 + +See also +[1] https://lists.freedesktop.org/archives/systemd-devel/2017-February/038326.html +[2] https://lists.freedesktop.org/archives/systemd-devel/2017-March/038397.html + +This reverts f073b1b but keeps the same symlinks for compatibility. + +(cherry picked from commit fb92fbb1b171ef94207a1ebc111ef0e414d49b4c) + +Resolves: #1496697 +--- + rules/60-persistent-storage.rules | 4 ++++ + src/udev/udev-builtin-path_id.c | 5 +---- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index 06e3329cc..10642a1fd 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -71,6 +71,10 @@ ENV{DEVTYPE}=="partition", ENV{ID_SAS_PATH}=="?*", SYMLINK+="disk/by-path/$env{I + # skip unpartitioned removable media devices from drivers which do not send "change" events + ENV{DEVTYPE}=="disk", KERNEL!="sd*|sr*", ATTR{removable}=="1", GOTO="persistent_storage_end" + ++# legacy virtio-pci by-path links (deprecated) ++KERNEL=="vd*[!0-9]", ENV{ID_PATH}=="pci-*", SYMLINK+="disk/by-path/virtio-$env{ID_PATH}" ++KERNEL=="vd*[0-9]", ENV{ID_PATH}=="pci-*", SYMLINK+="disk/by-path/virtio-$env{ID_PATH}-part%n" ++ + # probe filesystem metadata of optical drives which have a media inserted + KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="?*", \ + IMPORT{builtin}="blkid --offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}" +diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c +index 19447201b..d113ff21b 100644 +--- a/src/udev/udev-builtin-path_id.c ++++ b/src/udev/udev-builtin-path_id.c +@@ -688,11 +688,8 @@ restart: + 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)); ++ parent = skip_subsystem(parent, "virtio"); + 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/0540-socket-util-socket_address_parse-should-not-log-erro.patch b/SOURCES/0540-socket-util-socket_address_parse-should-not-log-erro.patch new file mode 100644 index 0000000..95d622a --- /dev/null +++ b/SOURCES/0540-socket-util-socket_address_parse-should-not-log-erro.patch @@ -0,0 +1,105 @@ +From b2dfc6d1b697da2e649b04ad0b8c3aef7a7d4d88 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 15 May 2015 20:15:59 +0200 +Subject: [PATCH] socket-util: socket_address_parse() should not log errors on + its own + +Given that socket_address_parse() is mostly a "library" call it +shouldn't log on its own, but leave that to its caller. + +This patch removes logging from the call in case IPv6 is not available +but and IPv6 address shall be parsed. Instead a new call +socket_address_parse_and_warn() is introduced which first invokes +socket_address_parse() and then logs if necessary. + +This should fix "make check" on ipv6-less kernels: + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/031385.html +(cherry picked from commit 7693146dee53a2b0f524e977188347166bf454ca) + +Related: #1497639 +--- + src/core/load-fragment.c | 2 +- + src/shared/socket-util.c | 29 +++++++++++++++++++---------- + src/shared/socket-util.h | 1 + + 3 files changed, 21 insertions(+), 11 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 58e44b89b..0c0fa0f50 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -365,7 +365,7 @@ int config_parse_socket_listen(const char *unit, + log_syntax(unit, LOG_ERR, filename, line, -r, + "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + +- r = socket_address_parse(&p->address, k ? k : rvalue); ++ r = socket_address_parse_and_warn(&p->address, k ? k : rvalue); + if (r < 0) { + if (r != -EAFNOSUPPORT) + log_syntax(unit, LOG_ERR, filename, line, -r, +diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c +index baab6353e..b14e36817 100644 +--- a/src/shared/socket-util.c ++++ b/src/shared/socket-util.c +@@ -55,11 +55,6 @@ int socket_address_parse(SocketAddress *a, const char *s) { + if (*s == '[') { + /* IPv6 in [x:.....:z]:p notation */ + +- if (!socket_ipv6_is_supported()) { +- log_warning("Binding to IPv6 address not available since kernel does not support IPv6."); +- return -EAFNOSUPPORT; +- } +- + e = strchr(s+1, ']'); + if (!e) + return -EINVAL; +@@ -144,11 +139,6 @@ int socket_address_parse(SocketAddress *a, const char *s) { + if (idx == 0) + return -EINVAL; + +- if (!socket_ipv6_is_supported()) { +- log_warning("Binding to interface is not available since kernel does not support IPv6."); +- return -EAFNOSUPPORT; +- } +- + a->sockaddr.in6.sin6_family = AF_INET6; + a->sockaddr.in6.sin6_port = htons((uint16_t) u); + a->sockaddr.in6.sin6_scope_id = idx; +@@ -182,6 +172,25 @@ int socket_address_parse(SocketAddress *a, const char *s) { + return 0; + } + ++int socket_address_parse_and_warn(SocketAddress *a, const char *s) { ++ SocketAddress b; ++ int r; ++ ++ /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */ ++ ++ r = socket_address_parse(&b, s); ++ if (r < 0) ++ return r; ++ ++ if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) { ++ log_warning("Binding to IPv6 address not available since kernel does not support IPv6."); ++ return -EAFNOSUPPORT; ++ } ++ ++ *a = b; ++ return 0; ++} ++ + int socket_address_parse_netlink(SocketAddress *a, const char *s) { + int family; + unsigned group = 0; +diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h +index 6bfb677fb..9200ce882 100644 +--- a/src/shared/socket-util.h ++++ b/src/shared/socket-util.h +@@ -67,6 +67,7 @@ typedef enum SocketAddressBindIPv6Only { + #define socket_address_family(a) ((a)->sockaddr.sa.sa_family) + + int socket_address_parse(SocketAddress *a, const char *s); ++int socket_address_parse_and_warn(SocketAddress *a, const char *s); + int socket_address_parse_netlink(SocketAddress *a, const char *s); + int socket_address_print(const SocketAddress *a, char **p); + int socket_address_verify(const SocketAddress *a) _pure_; diff --git a/SOURCES/0541-test-fix-failing-test-socket-util-when-running-with-.patch b/SOURCES/0541-test-fix-failing-test-socket-util-when-running-with-.patch new file mode 100644 index 0000000..fa938bd --- /dev/null +++ b/SOURCES/0541-test-fix-failing-test-socket-util-when-running-with-.patch @@ -0,0 +1,69 @@ +From 4fbaa65aff7eda3b3965e9c482b08532f3491800 Mon Sep 17 00:00:00 2001 +From: Marcin Bachry +Date: Wed, 11 Nov 2015 15:45:26 +0100 +Subject: [PATCH] test: fix failing test-socket-util when running with + ipv6.disable=1 kernel param + +The ability to use inet_pton(AF_INET6, ...) doesn't depend on kernel +ipv6 support (inet_pton is a pure libc function), so make ipv6 address +parsing tests unconditional. + +(cherry picked from commit 4ebc62ec87162aaa11e077f8693316ecf2d5c58d) + +Resolves: #1497639 +--- + src/test/test-socket-util.c | 41 +++++++++++++++++++---------------------- + 1 file changed, 19 insertions(+), 22 deletions(-) + +diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c +index 6fb4a4094..85f222993 100644 +--- a/src/test/test-socket-util.c ++++ b/src/test/test-socket-util.c +@@ -38,28 +38,25 @@ static void test_socket_address_parse(void) { + + assert_se(socket_address_parse(&a, "65535") >= 0); + +- if (socket_ipv6_is_supported()) { +- assert_se(socket_address_parse(&a, "[::1]") < 0); +- assert_se(socket_address_parse(&a, "[::1]8888") < 0); +- assert_se(socket_address_parse(&a, "::1") < 0); +- assert_se(socket_address_parse(&a, "[::1]:0") < 0); +- assert_se(socket_address_parse(&a, "[::1]:65536") < 0); +- assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0); +- +- assert_se(socket_address_parse(&a, "8888") >= 0); +- assert_se(a.sockaddr.sa.sa_family == AF_INET6); +- +- assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0); +- assert_se(a.sockaddr.sa.sa_family == AF_INET6); +- +- assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); +- assert_se(a.sockaddr.sa.sa_family == AF_INET6); +- } else { +- assert_se(socket_address_parse(&a, "[::1]:8888") < 0); +- +- assert_se(socket_address_parse(&a, "8888") >= 0); +- assert_se(a.sockaddr.sa.sa_family == AF_INET); +- } ++ /* The checks below will pass even if ipv6 is disabled in ++ * kernel. The underlying glibc's inet_pton() is just a string ++ * parser and doesn't make any syscalls. */ ++ ++ assert_se(socket_address_parse(&a, "[::1]") < 0); ++ assert_se(socket_address_parse(&a, "[::1]8888") < 0); ++ assert_se(socket_address_parse(&a, "::1") < 0); ++ assert_se(socket_address_parse(&a, "[::1]:0") < 0); ++ assert_se(socket_address_parse(&a, "[::1]:65536") < 0); ++ assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0); ++ ++ assert_se(socket_address_parse(&a, "8888") >= 0); ++ assert_se(a.sockaddr.sa.sa_family == (socket_ipv6_is_supported() ? AF_INET6 : AF_INET)); ++ ++ assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0); ++ assert_se(a.sockaddr.sa.sa_family == AF_INET6); ++ ++ assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); ++ assert_se(a.sockaddr.sa.sa_family == AF_INET6); + + assert_se(socket_address_parse(&a, "192.168.1.254:8888") >= 0); + assert_se(a.sockaddr.sa.sa_family == AF_INET); diff --git a/SOURCES/0542-scsi_id-add-missing-options-to-getopt_long-6501.patch b/SOURCES/0542-scsi_id-add-missing-options-to-getopt_long-6501.patch new file mode 100644 index 0000000..2f1e33b --- /dev/null +++ b/SOURCES/0542-scsi_id-add-missing-options-to-getopt_long-6501.patch @@ -0,0 +1,25 @@ +From c7eef2f4f985dd427b120fd00a36fd3d7f9a001a Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 2 Aug 2017 10:12:33 +0200 +Subject: [PATCH] scsi_id: add missing options to getopt_long() (#6501) + +(cherry picked from commit ebc6f34a0b2359ac0da41037a1122d3abe02caee) + +Resolves: #1476910 +--- + src/udev/scsi_id/scsi_id.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c +index a1b8e75fa..eae7e2955 100644 +--- a/src/udev/scsi_id/scsi_id.c ++++ b/src/udev/scsi_id/scsi_id.c +@@ -333,7 +333,7 @@ static int set_options(struct udev *udev, + * file) we have to reset this back to 1. + */ + optind = 1; +- while ((option = getopt_long(argc, argv, "d:f:gp:uvVxh", options, NULL)) >= 0) ++ while ((option = getopt_long(argc, argv, "d:f:gp:uvVxhbs:", options, NULL)) >= 0) + switch (option) { + case 'b': + all_good = false; diff --git a/SOURCES/0543-unmount-Pass-in-mount-options-when-remounting-read-o.patch b/SOURCES/0543-unmount-Pass-in-mount-options-when-remounting-read-o.patch new file mode 100644 index 0000000..addea4f --- /dev/null +++ b/SOURCES/0543-unmount-Pass-in-mount-options-when-remounting-read-o.patch @@ -0,0 +1,104 @@ +From 06456e9d3235921c13e0e2f86a68e41a930aae0c Mon Sep 17 00:00:00 2001 +From: Jan Janssen +Date: Mon, 26 Oct 2015 15:13:28 +0100 +Subject: [PATCH] unmount: Pass in mount options when remounting read-only + +man 2 mount says that the mountflags and data parameteres should +match the original values except for the desired changes. We only +bother with the mount options since the only flags we can change +are MS_RDONLY, MS_SYNCHRONOUS and MS_MANDLOCK; which shouldn't +matter too much. + +Fixes: #351 + +(cherry picked from commit 471b48ed2ff6539e7071ff4694c03483c5835639) + +Related: #1312002 +--- + src/core/umount.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/src/core/umount.c b/src/core/umount.c +index dd7df194d..bfd8aa5f8 100644 +--- a/src/core/umount.c ++++ b/src/core/umount.c +@@ -28,6 +28,7 @@ + #include + #include + ++#include "fstab-util.h" + #include "list.h" + #include "mount-setup.h" + #include "umount.h" +@@ -39,6 +40,7 @@ + + typedef struct MountPoint { + char *path; ++ char *options; + dev_t devnum; + LIST_FIELDS(struct MountPoint, mount_point); + } MountPoint; +@@ -71,7 +73,7 @@ static int mount_points_list_get(MountPoint **head) { + return -errno; + + for (i = 1;; i++) { +- _cleanup_free_ char *path = NULL; ++ _cleanup_free_ char *path = NULL, *options = NULL; + char *p = NULL; + MountPoint *m; + int k; +@@ -82,15 +84,15 @@ static int mount_points_list_get(MountPoint **head) { + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ +- "%*s" /* (6) mount options */ ++ "%*s" /* (6) mount flags */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%*s " /* (9) file system type */ + "%*s" /* (10) mount source */ +- "%*s" /* (11) mount options 2 */ ++ "%ms" /* (11) mount options */ + "%*[^\n]", /* some rubbish at the end */ +- &path); +- if (k != 1) { ++ &path, &options); ++ if (k != 2) { + if (k == EOF) + break; + +@@ -125,6 +127,9 @@ static int mount_points_list_get(MountPoint **head) { + } + + m->path = p; ++ m->options = options; ++ options = NULL; ++ + LIST_PREPEND(mount_point, *head, m); + } + +@@ -368,6 +373,14 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e + benefits, but might confuse the host, as we remount + the superblock here, not the bind mound. */ + if (detect_container(NULL) <= 0) { ++ _cleanup_free_ char *options = NULL; ++ /* MS_REMOUNT requires that the data parameter ++ * should be the same from the original mount ++ * except for the desired changes. Since we want ++ * to remount read-only, we should filter out ++ * rw (and ro too, because it confuses the kernel) */ ++ (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options); ++ + /* We always try to remount directories + * read-only first, before we go on and umount + * them. +@@ -384,7 +397,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e + * alias read-only we hence should be + * relatively safe regarding keeping the fs we + * can otherwise not see dirty. */ +- mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL); ++ log_info("Remounting '%s' read-only with options '%s'.", m->path, options); ++ (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options); + } + + /* Skip / and /usr since we cannot unmount that diff --git a/SOURCES/0544-shutdown-don-t-remount-ro-network-filesystems.-6588.patch b/SOURCES/0544-shutdown-don-t-remount-ro-network-filesystems.-6588.patch new file mode 100644 index 0000000..bc4ca5e --- /dev/null +++ b/SOURCES/0544-shutdown-don-t-remount-ro-network-filesystems.-6588.patch @@ -0,0 +1,76 @@ +From f70113f32c25b8d1c7d87eb812556c91b4b9b5c6 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Thu, 31 Aug 2017 02:48:25 +1000 +Subject: [PATCH] shutdown: don't remount,ro network filesystems. (#6588) + +systemd-shutdown is run after the network is stopped, +so remounting a network filesystem read-only can hang. +A simple umount is the most useful thing that can +be done for a network filesystem once the network is down. + +(cherry picked from commit 9cbc4547702aac28466c497f720038b9e2dc510c) + +Resolves: #1312002 +--- + src/core/umount.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/src/core/umount.c b/src/core/umount.c +index bfd8aa5f8..6e8ccc794 100644 +--- a/src/core/umount.c ++++ b/src/core/umount.c +@@ -41,6 +41,7 @@ + typedef struct MountPoint { + char *path; + char *options; ++ char *type; + dev_t devnum; + LIST_FIELDS(struct MountPoint, mount_point); + } MountPoint; +@@ -73,7 +74,7 @@ static int mount_points_list_get(MountPoint **head) { + return -errno; + + for (i = 1;; i++) { +- _cleanup_free_ char *path = NULL, *options = NULL; ++ _cleanup_free_ char *path = NULL, *options = NULL, *type = NULL; + char *p = NULL; + MountPoint *m; + int k; +@@ -87,11 +88,11 @@ static int mount_points_list_get(MountPoint **head) { + "%*s" /* (6) mount flags */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ +- "%*s " /* (9) file system type */ ++ "%ms " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%ms" /* (11) mount options */ + "%*[^\n]", /* some rubbish at the end */ +- &path, &options); ++ &path, &type, &options); + if (k != 2) { + if (k == EOF) + break; +@@ -129,6 +130,8 @@ static int mount_points_list_get(MountPoint **head) { + m->path = p; + m->options = options; + options = NULL; ++ m->type = type; ++ type = NULL; + + LIST_PREPEND(mount_point, *head, m); + } +@@ -371,8 +374,12 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e + /* If we are in a container, don't attempt to + read-only mount anything as that brings no real + benefits, but might confuse the host, as we remount +- the superblock here, not the bind mound. */ +- if (detect_container(NULL) <= 0) { ++ the superblock here, not the bind mount. ++ If the filesystem is a network fs, also skip the ++ remount. It brings no value (we cannot leave ++ a "dirty fs") and could hang if the network is down. */ ++ if (detect_container(NULL) <= 0 && ++ !fstype_is_network(m->type)) { + _cleanup_free_ char *options = NULL; + /* MS_REMOUNT requires that the data parameter + * should be the same from the original mount diff --git a/SOURCES/0545-shutdown-fix-incorrect-fscanf-result-check-6806.patch b/SOURCES/0545-shutdown-fix-incorrect-fscanf-result-check-6806.patch new file mode 100644 index 0000000..0b18ab2 --- /dev/null +++ b/SOURCES/0545-shutdown-fix-incorrect-fscanf-result-check-6806.patch @@ -0,0 +1,29 @@ +From 4ee75042124dbc675fa68d2dadfdcf866d772de8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 13 Sep 2017 10:08:37 +0200 +Subject: [PATCH] shutdown: fix incorrect fscanf() result check (#6806) + +A correction for 090e3c9796ef6468d4f396610804d62f6ffd797f. + +Fixes: #6796 + +(cherry-picked from: 3d4ec01269244c2d35a781abf748ea9ba57666e2) + +Related: #1312002 +--- + src/core/umount.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/umount.c b/src/core/umount.c +index 6e8ccc794..3eec0d459 100644 +--- a/src/core/umount.c ++++ b/src/core/umount.c +@@ -93,7 +93,7 @@ static int mount_points_list_get(MountPoint **head) { + "%ms" /* (11) mount options */ + "%*[^\n]", /* some rubbish at the end */ + &path, &type, &options); +- if (k != 2) { ++ if (k != 3) { + if (k == EOF) + break; + diff --git a/SOURCES/0546-path-util-make-use-of-mnt_id-field-exported-in-proc-.patch b/SOURCES/0546-path-util-make-use-of-mnt_id-field-exported-in-proc-.patch new file mode 100644 index 0000000..7e4c532 --- /dev/null +++ b/SOURCES/0546-path-util-make-use-of-mnt_id-field-exported-in-proc-.patch @@ -0,0 +1,407 @@ +From e5ac7ba7a16445f3ad23d9931979c20214eae913 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 14 Sep 2017 16:27:08 +0200 +Subject: [PATCH] path-util: make use of "mnt_id" field exported in + /proc/self/fdinfo/ + +This commit is not a backport of a specific commit. It includes parts of +several upstream commits (3f72b427b44f39a1aec6806dad6f6b57103ae9ed, +5d409034017e9f9f8c4392157d95511fc2e05d87 and others). + +The main goal was to bring path_is_mount_point() up to date, which meant +introducing fd_fdinfo_mnt_id() and fd_is_mount_point(). These were +needed mainly because we need to determine mount points based on +/proc/self/fdinfo/ in containers. Also, there are more places in the +code where checks for mount points are performed, which would benefit from +this fix as well. Additionally, corresponding tests has been added. + +Resolves: #1472439 +--- + src/nspawn/nspawn.c | 2 +- + src/shared/path-util.c | 219 ++++++++++++++++++++++++++++++++++++---------- + src/shared/path-util.h | 1 + + src/test/test-path-util.c | 62 +++++++++++++ + 4 files changed, 235 insertions(+), 49 deletions(-) + +diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c +index ea365b3f9..ee2e1832f 100644 +--- a/src/nspawn/nspawn.c ++++ b/src/nspawn/nspawn.c +@@ -990,7 +990,7 @@ static int mount_cgroup_hierarchy(const char *dest, const char *controller, cons + to = strjoina(dest, "/sys/fs/cgroup/", hierarchy); + + r = path_is_mount_point(to, false); +- if (r < 0) ++ if (r < 0 && r != -ENOENT) + return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to); + if (r > 0) + return 0; +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index 1181ffb9d..5d4de9ec4 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -36,6 +36,7 @@ + #include "strv.h" + #include "path-util.h" + #include "missing.h" ++#include "fileio.h" + + bool path_is_absolute(const char *p) { + return p[0] == '/'; +@@ -473,87 +474,209 @@ char* path_join(const char *root, const char *path, const char *rest) { + NULL); + } + +-int path_is_mount_point(const char *t, bool allow_symlink) { ++static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { ++ char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; ++ _cleanup_free_ char *fdinfo = NULL; ++ _cleanup_close_ int subfd = -1; ++ char *p; ++ int r; ++ ++ if ((flags & AT_EMPTY_PATH) && isempty(filename)) ++ xsprintf(path, "/proc/self/fdinfo/%i", fd); ++ else { ++ subfd = openat(fd, filename, O_CLOEXEC|O_PATH); ++ if (subfd < 0) ++ return -errno; + +- union file_handle_union h = FILE_HANDLE_INIT; ++ xsprintf(path, "/proc/self/fdinfo/%i", subfd); ++ } ++ ++ r = read_full_file(path, &fdinfo, NULL); ++ if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ ++ return -EOPNOTSUPP; ++ if (r < 0) ++ return -errno; ++ ++ p = startswith(fdinfo, "mnt_id:"); ++ if (!p) { ++ p = strstr(fdinfo, "\nmnt_id:"); ++ if (!p) /* The mnt_id field is a relatively new addition */ ++ return -EOPNOTSUPP; ++ ++ p += 8; ++ } ++ ++ p += strspn(p, WHITESPACE); ++ p[strcspn(p, WHITESPACE)] = 0; ++ ++ return safe_atoi(p, mnt_id); ++} ++ ++int fd_is_mount_point(int fd, const char *filename, int flags) { ++ union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; + int mount_id = -1, mount_id_parent = -1; +- _cleanup_free_ char *parent = NULL; ++ bool nosupp = false, check_st_dev = true; + struct stat a, b; + int r; +- bool nosupp = false; + +- /* We are not actually interested in the file handles, but +- * name_to_handle_at() also passes us the mount ID, hence use +- * it but throw the handle away */ ++ assert(fd >= 0); ++ assert(filename); + +- if (path_equal(t, "/")) +- return 1; +- +- r = name_to_handle_at(AT_FDCWD, t, &h.handle, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0); ++ /* First we will try the name_to_handle_at() syscall, which ++ * tells us the mount id and an opaque file "handle". It is ++ * not supported everywhere though (kernel compile-time ++ * option, not all file systems are hooked up). If it works ++ * the mount id is usually good enough to tell us whether ++ * something is a mount point. ++ * ++ * If that didn't work we will try to read the mount id from ++ * /proc/self/fdinfo/. This is almost as good as ++ * name_to_handle_at(), however, does not return the ++ * opaque file handle. The opaque file handle is pretty useful ++ * to detect the root directory, which we should always ++ * consider a mount point. Hence we use this only as ++ * fallback. Exporting the mnt_id in fdinfo is a pretty recent ++ * kernel addition. ++ * ++ * As last fallback we do traditional fstat() based st_dev ++ * comparisons. This is how things were traditionally done, ++ * but unionfs breaks this since it exposes file ++ * systems with a variety of st_dev reported. Also, btrfs ++ * subvolumes have different st_dev, even though they aren't ++ * real mounts of their own. */ ++ ++ r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); + if (r < 0) { +- if (errno == ENOSYS) +- /* This kernel does not support name_to_handle_at() +- * fall back to the traditional stat() logic. */ +- goto fallback; ++ if (IN_SET(errno, ENOSYS, EACCES, EPERM)) ++ /* This kernel does not support name_to_handle_at() at all, or the syscall was blocked (maybe ++ * through seccomp, because we are running inside of a container?): fall back to simpler ++ * logic. */ ++ goto fallback_fdinfo; + else if (errno == EOPNOTSUPP) + /* This kernel or file system does not support +- * name_to_handle_at(), hence fallback to the ++ * name_to_handle_at(), hence let's see if the ++ * upper fs supports it (in which case it is a ++ * mount point), otherwise fallback to the + * traditional stat() logic */ + nosupp = true; +- else if (errno == ENOENT) +- return 0; + else + return -errno; + } + +- r = path_get_parent(t, &parent); +- if (r < 0) +- return r; +- +- h.handle.handle_bytes = MAX_HANDLE_SZ; +- r = name_to_handle_at(AT_FDCWD, parent, &h.handle, &mount_id_parent, AT_SYMLINK_FOLLOW); +- if (r < 0) +- if (errno == EOPNOTSUPP) ++ r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); ++ if (r < 0) { ++ if (errno == EOPNOTSUPP) { + if (nosupp) + /* Neither parent nor child do name_to_handle_at()? + We have no choice but to fall back. */ +- goto fallback; ++ goto fallback_fdinfo; + else +- /* The parent can't do name_to_handle_at() but +- * the directory we are interested in can? +- * Or the other way around? ++ /* The parent can't do name_to_handle_at() but the ++ * directory we are interested in can? + * If so, it must be a mount point. */ + return 1; +- else ++ } else + return -errno; +- else +- return mount_id != mount_id_parent; ++ } + +-fallback: +- if (allow_symlink) +- r = stat(t, &a); +- else +- r = lstat(t, &a); ++ /* The parent can do name_to_handle_at() but the ++ * directory we are interested in can't? If so, it ++ * must be a mount point. */ ++ if (nosupp) ++ return 1; + +- if (r < 0) { +- if (errno == ENOENT) +- return 0; ++ /* If the file handle for the directory we are ++ * interested in and its parent are identical, we ++ * assume this is the root directory, which is a mount ++ * point. */ + +- return -errno; +- } ++ if (h.handle.handle_bytes == h_parent.handle.handle_bytes && ++ h.handle.handle_type == h_parent.handle.handle_type && ++ memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) ++ return 1; + +- free(parent); +- parent = NULL; ++ return mount_id != mount_id_parent; + +- r = path_get_parent(t, &parent); ++fallback_fdinfo: ++ r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); ++ if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM)) ++ goto fallback_fstat; + if (r < 0) + return r; + +- r = stat(parent, &b); ++ r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); + if (r < 0) ++ return r; ++ ++ if (mount_id != mount_id_parent) ++ return 1; ++ ++ /* Hmm, so, the mount ids are the same. This leaves one ++ * special case though for the root file system. For that, ++ * let's see if the parent directory has the same inode as we ++ * are interested in. Hence, let's also do fstat() checks now, ++ * too, but avoid the st_dev comparisons, since they aren't ++ * that useful on unionfs mounts. */ ++ check_st_dev = false; ++ ++fallback_fstat: ++ /* yay for fstatat() taking a different set of flags than the other ++ * _at() above */ ++ if (flags & AT_SYMLINK_FOLLOW) ++ flags &= ~AT_SYMLINK_FOLLOW; ++ else ++ flags |= AT_SYMLINK_NOFOLLOW; ++ if (fstatat(fd, filename, &a, flags) < 0) ++ return -errno; ++ ++ if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) ++ return -errno; ++ ++ /* A directory with same device and inode as its parent? Must ++ * be the root directory */ ++ if (a.st_dev == b.st_dev && ++ a.st_ino == b.st_ino) ++ return 1; ++ ++ return check_st_dev && (a.st_dev != b.st_dev); ++} ++ ++ ++ ++int path_is_mount_point(const char *t, bool allow_symlink) { ++ _cleanup_free_ char *canonical = NULL, *parent = NULL; ++ _cleanup_close_ int fd = -1; ++ int flags = allow_symlink ? AT_SYMLINK_FOLLOW : 0; ++ ++ assert(t); ++ ++ if (path_equal(t, "/")) ++ return 1; ++ ++ /* we need to resolve symlinks manually, we can't just rely on ++ * fd_is_mount_point() to do that for us; if we have a structure like ++ * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we ++ * look at needs to be /usr, not /. */ ++ if (flags & AT_SYMLINK_FOLLOW) { ++ canonical = canonicalize_file_name(t); ++ if (!canonical) { ++ if (errno == ENOENT) ++ return 0; ++ else ++ return -errno; ++ } ++ t = canonical; ++ } ++ ++ parent = dirname_malloc(t); ++ if (!parent) ++ return -ENOMEM; ++ ++ fd = openat(AT_FDCWD, parent, O_DIRECTORY|O_CLOEXEC|O_PATH); ++ if (fd < 0) + return -errno; + +- return a.st_dev != b.st_dev; ++ return fd_is_mount_point(fd, basename(t), flags); + } + + int path_is_read_only_fs(const char *path) { +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index 71bb740e9..34c016229 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -53,6 +53,7 @@ char** path_strv_make_absolute_cwd(char **l); + char** path_strv_resolve(char **l, const char *prefix); + char** path_strv_resolve_uniq(char **l, const char *prefix); + ++int fd_is_mount_point(int fd, const char *filename, int flags); + int path_is_mount_point(const char *path, bool allow_symlink); + int path_is_read_only_fs(const char *path); + int path_is_os_tree(const char *path); +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index 6396fcb39..a4fec07e7 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -21,6 +21,7 @@ + + #include + #include ++#include + + #include "path-util.h" + #include "util.h" +@@ -99,6 +100,66 @@ static void test_path(void) { + } + } + ++static void test_path_is_mount_point(void) { ++ int fd, rt, rf, rlt, rlf; ++ char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX"; ++ _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL; ++ ++ assert_se(path_is_mount_point("/", true) > 0); ++ assert_se(path_is_mount_point("/", false) > 0); ++ ++ assert_se(path_is_mount_point("/proc", true) > 0); ++ assert_se(path_is_mount_point("/proc", false) > 0); ++ ++ assert_se(path_is_mount_point("/proc/1", true) == 0); ++ assert_se(path_is_mount_point("/proc/1", false) == 0); ++ ++ assert_se(path_is_mount_point("/sys", true) > 0); ++ assert_se(path_is_mount_point("/sys", false) > 0); ++ ++ /* file mountpoints */ ++ assert_se(mkdtemp(tmp_dir) != NULL); ++ file1 = path_join(NULL, tmp_dir, "file1"); ++ assert_se(file1); ++ file2 = path_join(NULL, tmp_dir, "file2"); ++ assert_se(file2); ++ fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); ++ assert_se(fd > 0); ++ close(fd); ++ fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664); ++ assert_se(fd > 0); ++ close(fd); ++ link1 = path_join(NULL, tmp_dir, "link1"); ++ assert_se(link1); ++ assert_se(symlink("file1", link1) == 0); ++ link2 = path_join(NULL, tmp_dir, "link2"); ++ assert_se(link1); ++ assert_se(symlink("file2", link2) == 0); ++ ++ assert_se(path_is_mount_point(file1, true) == 0); ++ assert_se(path_is_mount_point(file1, false) == 0); ++ assert_se(path_is_mount_point(link1, true) == 0); ++ assert_se(path_is_mount_point(link1, false) == 0); ++ ++ /* this test will only work as root */ ++ if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) { ++ rf = path_is_mount_point(file2, false); ++ rt = path_is_mount_point(file2, true); ++ rlf = path_is_mount_point(link2, false); ++ rlt = path_is_mount_point(link2, true); ++ ++ assert_se(umount(file2) == 0); ++ ++ assert_se(rf == 1); ++ assert_se(rt == 1); ++ assert_se(rlf == 0); ++ assert_se(rlt == 1); ++ } else ++ printf("Skipping bind mount file test: %m\n"); ++ ++ assert_se(rm_rf(tmp_dir, false, true, false) == 0); ++} ++ + static void test_find_binary(const char *self, bool local) { + char *p; + +@@ -288,6 +349,7 @@ int main(int argc, char **argv) { + test_make_relative(); + test_strv_resolve(); + test_path_startswith(); ++ test_path_is_mount_point(); + + return 0; + } diff --git a/SOURCES/0547-support-ranges-when-parsing-CPUAffinity.patch b/SOURCES/0547-support-ranges-when-parsing-CPUAffinity.patch new file mode 100644 index 0000000..971fe38 --- /dev/null +++ b/SOURCES/0547-support-ranges-when-parsing-CPUAffinity.patch @@ -0,0 +1,621 @@ +From 6e00430563108b98230abd7407ac54fde61ae93c Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 26 Sep 2017 12:34:19 +0200 +Subject: [PATCH] support ranges when parsing CPUAffinity + +The functionality was implemented in https://github.com/systemd/systemd/pull/1699/. +However, it is not backportable without considerable code changes. + +Implement parse_range() and parse_cpu_set_and_warn() from the upstream master +branch and use them in appropriate places. Also introduce relevant tests. + +Resolves: #1493976 +--- + src/core/load-fragment.c | 49 +++----- + src/core/main.c | 48 ++------ + src/shared/util.c | 91 +++++++++++++++ + src/shared/util.h | 9 ++ + src/test/test-util.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 417 insertions(+), 76 deletions(-) + +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 0c0fa0f50..a10e1903a 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -884,50 +884,29 @@ int config_parse_exec_cpu_affinity(const char *unit, + void *userdata) { + + ExecContext *c = data; +- const char *word, *state; +- size_t l; ++ _cleanup_cpu_free_ cpu_set_t *cpuset = NULL; ++ int ncpus; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + +- if (isempty(rvalue)) { +- /* An empty assignment resets the CPU list */ +- if (c->cpuset) +- CPU_FREE(c->cpuset); +- c->cpuset = NULL; +- return 0; +- } +- +- FOREACH_WORD_QUOTED(word, l, rvalue, state) { +- _cleanup_free_ char *t = NULL; +- int r; +- unsigned cpu; +- +- t = strndup(word, l); +- if (!t) +- return log_oom(); +- +- r = safe_atou(t, &cpu); ++ ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue); ++ if (ncpus < 0) ++ return ncpus; + +- if (!c->cpuset) { +- c->cpuset = cpu_set_malloc(&c->cpuset_ncpus); +- if (!c->cpuset) +- return log_oom(); +- } ++ if (c->cpuset) ++ CPU_FREE(c->cpuset); + +- if (r < 0 || cpu >= c->cpuset_ncpus) { +- log_syntax(unit, LOG_ERR, filename, line, ERANGE, +- "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue); +- return 0; +- } +- +- CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset); ++ if (ncpus == 0) ++ /* An empty assignment resets the CPU list */ ++ c->cpuset = NULL; ++ else { ++ c->cpuset = cpuset; ++ cpuset = NULL; + } +- if (!isempty(state)) +- log_syntax(unit, LOG_WARNING, filename, line, EINVAL, +- "Trailing garbage, ignoring."); ++ c->cpuset_ncpus = ncpus; + + return 0; + } +diff --git a/src/core/main.c b/src/core/main.c +index 66393ed6a..5554ef468 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -438,49 +438,15 @@ static int config_parse_cpu_affinity2( + void *data, + void *userdata) { + +- const char *word, *state; +- size_t l; +- cpu_set_t *c = NULL; +- unsigned ncpus = 0; +- +- assert(filename); +- assert(lvalue); +- assert(rvalue); ++ _cleanup_cpu_free_ cpu_set_t *c = NULL; ++ int ncpus; + +- FOREACH_WORD_QUOTED(word, l, rvalue, state) { +- char *t; +- int r; +- unsigned cpu; +- +- if (!(t = strndup(word, l))) +- return log_oom(); +- +- r = safe_atou(t, &cpu); +- free(t); +- +- if (!c) +- if (!(c = cpu_set_malloc(&ncpus))) +- return log_oom(); ++ ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue); ++ if (ncpus < 0) ++ return ncpus; + +- if (r < 0 || cpu >= ncpus) { +- log_syntax(unit, LOG_ERR, filename, line, -r, +- "Failed to parse CPU affinity '%s'", rvalue); +- CPU_FREE(c); +- return -EBADMSG; +- } +- +- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); +- } +- if (!isempty(state)) +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, +- "Trailing garbage, ignoring."); +- +- if (c) { +- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) +- log_unit_warning(unit, "Failed to set CPU affinity: %m"); +- +- CPU_FREE(c); +- } ++ if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) ++ log_warning_errno(errno, "Failed to set CPU affinity: %m"); + + return 0; + } +diff --git a/src/shared/util.c b/src/shared/util.c +index bbb457759..39359fcc8 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -2727,6 +2727,43 @@ int parse_size(const char *t, off_t base, off_t *size) { + return 0; + } + ++int parse_range(const char *t, unsigned *lower, unsigned *upper) { ++ _cleanup_free_ char *word = NULL; ++ unsigned l, u; ++ int r; ++ ++ assert(lower); ++ assert(upper); ++ ++ /* Extract the lower bound. */ ++ r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS); ++ if (r < 0) ++ return r; ++ if (r == 0) ++ return -EINVAL; ++ ++ r = safe_atou(word, &l); ++ if (r < 0) ++ return r; ++ ++ /* Check for the upper bound and extract it if needed */ ++ if (!t) ++ /* Single number with no dashes. */ ++ u = l; ++ else if (!*t) ++ /* Trailing dash is an error. */ ++ return -EINVAL; ++ else { ++ r = safe_atou(t, &u); ++ if (r < 0) ++ return r; ++ } ++ ++ *lower = l; ++ *upper = u; ++ return 0; ++} ++ + int make_stdio(int fd) { + int r, s, t; + +@@ -3460,6 +3497,60 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) { + } + } + ++int parse_cpu_set_and_warn( ++ const char *rvalue, ++ cpu_set_t **cpu_set, ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *lvalue) { ++ ++ const char *whole_rvalue = rvalue; ++ _cleanup_cpu_free_ cpu_set_t *c = NULL; ++ unsigned ncpus = 0; ++ ++ assert(lvalue); ++ assert(rvalue); ++ ++ for (;;) { ++ _cleanup_free_ char *word = NULL; ++ unsigned cpu, cpu_lower, cpu_upper; ++ int r; ++ ++ r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES); ++ if (r < 0) ++ return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); ++ if (r == 0) ++ break; ++ ++ if (!c) { ++ c = cpu_set_malloc(&ncpus); ++ if (!c) ++ return log_oom(); ++ } ++ ++ r = parse_range(word, &cpu_lower, &cpu_upper); ++ if (r < 0) ++ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word); ++ if (cpu_lower >= ncpus || cpu_upper >= ncpus) ++ return log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus); ++ ++ if (cpu_lower > cpu_upper) ++ log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u", word, cpu_lower, cpu_upper); ++ else ++ for (cpu = cpu_lower; cpu <= cpu_upper; cpu++) ++ CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); ++ } ++ ++ /* On success, sets *cpu_set and returns ncpus for the system. */ ++ if (c) { ++ *cpu_set = c; ++ c = NULL; ++ } ++ ++ return (int) ncpus; ++} ++ + int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { + static const char status_indent[] = " "; /* "[" STATUS "] " */ + _cleanup_free_ char *s = NULL; +diff --git a/src/shared/util.h b/src/shared/util.h +index 80ad18c0a..526a6fe84 100644 +--- a/src/shared/util.h ++++ b/src/shared/util.h +@@ -136,6 +136,11 @@ bool streq_ptr(const char *a, const char *b) _pure_; + + #define malloc0(n) (calloc((n), 1)) + ++static inline void *mfree(void *memory) { ++ free(memory); ++ return NULL; ++} ++ + static inline const char* yes_no(bool b) { + return b ? "yes" : "no"; + } +@@ -195,6 +200,7 @@ void safe_close_pair(int p[]); + void close_many(const int fds[], unsigned n_fd); + + int parse_size(const char *t, off_t base, off_t *size); ++int parse_range(const char *t, unsigned *lower, unsigned *upper); + + int parse_boolean(const char *v) _pure_; + int parse_pid(const char *s, pid_t* ret_pid); +@@ -474,6 +480,7 @@ int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool hon + int pipe_eof(int fd); + + cpu_set_t* cpu_set_malloc(unsigned *ncpus); ++int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue); + + int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0); + int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5); +@@ -692,6 +699,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose); + DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); + DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); + DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); ++DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); + + #define _cleanup_free_ _cleanup_(freep) + #define _cleanup_close_ _cleanup_(closep) +@@ -702,6 +710,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); + #define _cleanup_closedir_ _cleanup_(closedirp) + #define _cleanup_endmntent_ _cleanup_(endmntentp) + #define _cleanup_close_pair_ _cleanup_(close_pairp) ++#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) + + _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) +diff --git a/src/test/test-util.c b/src/test/test-util.c +index 971f97d7c..fcf5416c0 100644 +--- a/src/test/test-util.c ++++ b/src/test/test-util.c +@@ -689,6 +689,300 @@ static void test_parse_size(void) { + assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); + } + ++static void test_parse_range(void) { ++ unsigned lower, upper; ++ ++ /* Successful cases */ ++ assert_se(parse_range("111", &lower, &upper) == 0); ++ assert_se(lower == 111); ++ assert_se(upper == 111); ++ ++ assert_se(parse_range("111-123", &lower, &upper) == 0); ++ assert_se(lower == 111); ++ assert_se(upper == 123); ++ ++ assert_se(parse_range("123-111", &lower, &upper) == 0); ++ assert_se(lower == 123); ++ assert_se(upper == 111); ++ ++ assert_se(parse_range("123-123", &lower, &upper) == 0); ++ assert_se(lower == 123); ++ assert_se(upper == 123); ++ ++ assert_se(parse_range("0", &lower, &upper) == 0); ++ assert_se(lower == 0); ++ assert_se(upper == 0); ++ ++ assert_se(parse_range("0-15", &lower, &upper) == 0); ++ assert_se(lower == 0); ++ assert_se(upper == 15); ++ ++ assert_se(parse_range("15-0", &lower, &upper) == 0); ++ assert_se(lower == 15); ++ assert_se(upper == 0); ++ ++ assert_se(parse_range("128-65535", &lower, &upper) == 0); ++ assert_se(lower == 128); ++ assert_se(upper == 65535); ++ ++ assert_se(parse_range("1024-4294967295", &lower, &upper) == 0); ++ assert_se(lower == 1024); ++ assert_se(upper == 4294967295); ++ ++ /* Leading whitespace is acceptable */ ++ assert_se(parse_range(" 111", &lower, &upper) == 0); ++ assert_se(lower == 111); ++ assert_se(upper == 111); ++ ++ assert_se(parse_range(" 111-123", &lower, &upper) == 0); ++ assert_se(lower == 111); ++ assert_se(upper == 123); ++ ++ assert_se(parse_range("111- 123", &lower, &upper) == 0); ++ assert_se(lower == 111); ++ assert_se(upper == 123); ++ ++ assert_se(parse_range("\t111-\t123", &lower, &upper) == 0); ++ assert_se(lower == 111); ++ assert_se(upper == 123); ++ ++ assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0); ++ assert_se(lower == 111); ++ assert_se(upper == 123); ++ ++ /* Error cases, make sure they fail as expected */ ++ lower = upper = 9999; ++ assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("garbage", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ /* Empty string */ ++ lower = upper = 9999; ++ assert_se(parse_range("", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */ ++ assert_se(parse_range("111--123", &lower, &upper) == -ERANGE); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ /* Error on trailing dash */ ++ assert_se(parse_range("111-", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111--", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111- ", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ /* Whitespace is not a separator */ ++ assert_se(parse_range("111 123", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ /* Trailing whitespace is invalid (from safe_atou) */ ++ assert_se(parse_range("111 ", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++ ++ /* Out of the "unsigned" range, this is 1<<64 */ ++ assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE); ++ assert_se(lower == 9999); ++ assert_se(upper == 9999); ++} ++ ++static void test_parse_cpu_set(void) { ++ cpu_set_t *c = NULL; ++ int ncpus; ++ int cpu; ++ ++ /* Simple range (from CPUAffinity example) */ ++ ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); ++ c = mfree(c); ++ ++ /* A more interesting range */ ++ ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ for (cpu = 0; cpu < 4; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ for (cpu = 8; cpu < 12; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ c = mfree(c); ++ ++ /* Quoted strings */ ++ ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); ++ for (cpu = 8; cpu < 12; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ c = mfree(c); ++ ++ /* Use commas as separators */ ++ ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ for (cpu = 0; cpu < 4; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ for (cpu = 8; cpu < 12; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ c = mfree(c); ++ ++ /* Commas with spaces (and trailing comma, space) */ ++ ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ for (cpu = 0; cpu < 8; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ c = mfree(c); ++ ++ /* Ranges */ ++ ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ for (cpu = 0; cpu < 4; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ for (cpu = 8; cpu < 12; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ c = mfree(c); ++ ++ /* Ranges with trailing comma, space */ ++ ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); ++ for (cpu = 0; cpu < 4; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ for (cpu = 8; cpu < 12; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ c = mfree(c); ++ ++ /* Negative range (returns empty cpu_set) */ ++ ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); ++ c = mfree(c); ++ ++ /* Overlapping ranges */ ++ ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); ++ for (cpu = 0; cpu < 12; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ c = mfree(c); ++ ++ /* Mix ranges and individual CPUs */ ++ ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus >= 1024); ++ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); ++ assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); ++ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); ++ for (cpu = 4; cpu < 12; cpu++) ++ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); ++ c = mfree(c); ++ ++ /* Garbage */ ++ ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus < 0); ++ assert_se(!c); ++ ++ /* Range with garbage */ ++ ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus < 0); ++ assert_se(!c); ++ ++ /* Empty string */ ++ c = NULL; ++ ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus == 0); /* empty string returns 0 */ ++ assert_se(!c); ++ ++ /* Runaway quoted string */ ++ ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); ++ assert_se(ncpus < 0); ++ assert_se(!c); ++} ++ + static void test_config_parse_iec_off(void) { + off_t offset = 0; + assert_se(config_parse_iec_off(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); +@@ -1605,6 +1899,8 @@ int main(int argc, char *argv[]) { + test_get_process_comm(); + test_protect_errno(); + test_parse_size(); ++ test_parse_range(); ++ test_parse_cpu_set(); + test_config_parse_iec_off(); + test_strextend(); + test_strrep(); diff --git a/SOURCES/0548-man-Update-man-page-documentation-for-CPUAffinity.patch b/SOURCES/0548-man-Update-man-page-documentation-for-CPUAffinity.patch new file mode 100644 index 0000000..3eebde9 --- /dev/null +++ b/SOURCES/0548-man-Update-man-page-documentation-for-CPUAffinity.patch @@ -0,0 +1,51 @@ +From 99afbf6e7fac9f33f0f96c0397c413ba360607a2 Mon Sep 17 00:00:00 2001 +From: Filipe Brandenburger +Date: Tue, 13 Oct 2015 00:12:39 -0700 +Subject: [PATCH] man: Update man page documentation for CPUAffinity + +Document support for commas as a separator and possibility of specifying +ranges of CPU indices. + +Tested by regenerating the manpages locally and reading them on man. + +(cherry picked from commit 71b1c27a406271b71f64487ae70b58f44a4a37f0) +Resolves: #1493976 +--- + man/systemd-system.conf.xml | 6 ++++-- + man/systemd.exec.xml | 6 ++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml +index 53e8ff665..1861bb03f 100644 +--- a/man/systemd-system.conf.xml ++++ b/man/systemd-system.conf.xml +@@ -117,8 +117,10 @@ + CPUAffinity= + + Configures the initial CPU affinity for the +- init process. Takes a space-separated list of CPU +- indices. ++ init process. Takes a list of CPU indices or ranges separated ++ by either whitespace or commas. CPU ranges are specified by ++ the lower and upper CPU indices separated by a ++ dash. + + + +diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml +index 508146f06..d7503b8e8 100644 +--- a/man/systemd.exec.xml ++++ b/man/systemd.exec.xml +@@ -211,8 +211,10 @@ + CPUAffinity= + + Controls the CPU affinity of the executed +- processes. Takes a space-separated list of CPU indices. This +- option may be specified more than once in which case the ++ processes. Takes a list of CPU indices or ranges separated by ++ either whitespace or commas. CPU ranges are specified by the ++ lower and upper CPU indices separated by a dash. ++ This option may be specified more than once in which case the + specified CPU affinity masks are merged. If the empty string + is assigned, the mask is reset, all assignments prior to this + will have no effect. See diff --git a/SOURCES/0549-test-path-util-force-rm_rf.patch b/SOURCES/0549-test-path-util-force-rm_rf.patch new file mode 100644 index 0000000..eb867e1 --- /dev/null +++ b/SOURCES/0549-test-path-util-force-rm_rf.patch @@ -0,0 +1,28 @@ +From 6e3239eed032eaf0c9a6308664a9034e64c98d30 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Fri, 13 Oct 2017 13:29:14 +0200 +Subject: [PATCH] test-path-util: force rm_rf + +On rhel we don't have tmpfs in /tmp, so simple rm_rf will +refuse to remove the test directory. + +RHEL-only + +Related: #1472439 +--- + src/test/test-path-util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c +index a4fec07e7..aee1f4e03 100644 +--- a/src/test/test-path-util.c ++++ b/src/test/test-path-util.c +@@ -157,7 +157,7 @@ static void test_path_is_mount_point(void) { + } else + printf("Skipping bind mount file test: %m\n"); + +- assert_se(rm_rf(tmp_dir, false, true, false) == 0); ++ assert_se(rm_rf_dangerous(tmp_dir, false, true, false) == 0); + } + + static void test_find_binary(const char *self, bool local) { diff --git a/SOURCES/0550-Export-NVMe-WWID-udev-attribute-5348.patch b/SOURCES/0550-Export-NVMe-WWID-udev-attribute-5348.patch new file mode 100644 index 0000000..e4e4964 --- /dev/null +++ b/SOURCES/0550-Export-NVMe-WWID-udev-attribute-5348.patch @@ -0,0 +1,28 @@ +From c9c86577937088e36bcfb67e701aebe51d2cc893 Mon Sep 17 00:00:00 2001 +From: Keith Busch +Date: Fri, 17 Feb 2017 00:46:06 -0700 +Subject: [PATCH] Export NVMe WWID udev attribute (#5348) + +We need this for multipath support without relying on NVMe to SCSI +translations. + +Signed-off-by: Keith Busch + +Cherry-picked from: 5c1be4f73082d09011661516c39fb53626d8bdc7 +Resolves: #1503253 +--- + rules/60-persistent-storage.rules | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules +index 10642a1fd..ba619633b 100644 +--- a/rules/60-persistent-storage.rules ++++ b/rules/60-persistent-storage.rules +@@ -27,6 +27,7 @@ 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{wwid}=="?*", ENV{ID_WWN}="$attr{wwid}" + 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}" diff --git a/SOURCES/0551-mount-make-sure-we-unmount-tmpfs-mounts-before-we-de.patch b/SOURCES/0551-mount-make-sure-we-unmount-tmpfs-mounts-before-we-de.patch new file mode 100644 index 0000000..6115327 --- /dev/null +++ b/SOURCES/0551-mount-make-sure-we-unmount-tmpfs-mounts-before-we-de.patch @@ -0,0 +1,122 @@ +From e7e3e1d230c15079a3d1480c47076ffd89f1de63 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 16 Oct 2017 16:15:05 +0200 +Subject: [PATCH] mount: make sure we unmount tmpfs mounts before we deactivate + swaps (#7076) + +In the past we introduced this property just for tmp.mount. However on +todays systems usually there are many more tmpfs mounts. Most notably +mounts backing XDG_RUNTIME_DIR for each user. + +Let's generalize what we already have for tmp.mount and implement the +ordering After=swap.target for all tmpfs based mounts. + +(cherry picked from commit fab35afabf01a5dea651187a1ccb5ae7cd778f9d) + +Conflicts: + src/core/mount.h + +Resolves: #1437518 +--- + src/core/dbus-mount.c | 10 +--------- + src/core/mount.c | 24 ++++++++++++++++++++++++ + src/core/mount.h | 1 + + units/tmp.mount | 1 - + 4 files changed, 26 insertions(+), 10 deletions(-) + +diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c +index 53fe4edc3..04beba631 100644 +--- a/src/core/dbus-mount.c ++++ b/src/core/dbus-mount.c +@@ -90,20 +90,12 @@ static int property_get_type( + sd_bus_error *error) { + + Mount *m = userdata; +- const char *d; + + assert(bus); + assert(reply); + assert(m); + +- if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype) +- d = m->parameters_proc_self_mountinfo.fstype; +- else if (m->from_fragment && m->parameters_fragment.fstype) +- d = m->parameters_fragment.fstype; +- else +- d = ""; +- +- return sd_bus_message_append(reply, "s", d); ++ return sd_bus_message_append(reply, "s", mount_get_fstype(m)); + } + + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResult); +diff --git a/src/core/mount.c b/src/core/mount.c +index 7ca7f5a25..a6d93b869 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -119,6 +119,21 @@ static bool needs_quota(const MountParameters *p) { + "usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0"); + } + ++const char *mount_get_fstype(const Mount *m) { ++ const char *type = NULL; ++ ++ assert(m); ++ ++ if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype) ++ type = m->parameters_proc_self_mountinfo.fstype; ++ else if (m->from_fragment && m->parameters_fragment.fstype) ++ type = m->parameters_fragment.fstype; ++ else ++ type = ""; ++ ++ return type; ++} ++ + static void mount_init(Unit *u) { + Mount *m = MOUNT(u); + +@@ -236,6 +251,7 @@ _pure_ static MountParameters* get_mount_parameters(Mount *m) { + + static int mount_add_mount_links(Mount *m) { + _cleanup_free_ char *parent = NULL; ++ const char *fstype; + MountParameters *pm; + Unit *other; + Iterator i; +@@ -292,6 +308,14 @@ static int mount_add_mount_links(Mount *m) { + } + } + ++ /* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */ ++ fstype = mount_get_fstype(m); ++ if (streq(fstype, "tmpfs")) { ++ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true); ++ if (r < 0) ++ return r; ++ } ++ + return 0; + } + +diff --git a/src/core/mount.h b/src/core/mount.h +index d6987e6fa..353222000 100644 +--- a/src/core/mount.h ++++ b/src/core/mount.h +@@ -130,3 +130,4 @@ const char* mount_result_to_string(MountResult i) _const_; + MountResult mount_result_from_string(const char *s) _pure_; + + void warn_if_dir_nonempty(const char *unit, const char* where); ++const char *mount_get_fstype(const Mount *m); +diff --git a/units/tmp.mount b/units/tmp.mount +index 8c53a8705..af0cf4a55 100644 +--- a/units/tmp.mount ++++ b/units/tmp.mount +@@ -13,7 +13,6 @@ ConditionPathIsSymbolicLink=!/tmp + DefaultDependencies=no + Conflicts=umount.target + Before=local-fs.target umount.target +-After=swap.target + + [Mount] + What=tmpfs diff --git a/SOURCES/0552-journald-never-accept-fds-from-file-systems-with-man.patch b/SOURCES/0552-journald-never-accept-fds-from-file-systems-with-man.patch new file mode 100644 index 0000000..6203c9e --- /dev/null +++ b/SOURCES/0552-journald-never-accept-fds-from-file-systems-with-man.patch @@ -0,0 +1,67 @@ +From 6d9aff83ef5d50a65fad4f4218073bd4aa3e6902 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 10 Nov 2015 20:08:04 +0100 +Subject: [PATCH] journald: never accept fds from file systems with mandatory + locking enabled + +This is pretty much a work-around for a security vulnerability in +kernels that allow unprivileged user namespaces. + +Fixes #1822. + +Cherry-picked from: 1e603a482f57edb1fb863dbf23b868cf5854e004 +Resolves: #1501017 +--- + src/journal/journald-native.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c +index 2c9cf6e7a..fdb1a38dd 100644 +--- a/src/journal/journald-native.c ++++ b/src/journal/journald-native.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include "socket-util.h" + #include "path-util.h" +@@ -391,8 +392,37 @@ void server_process_native_file( + assert_se(munmap(p, ps) >= 0); + } else { + _cleanup_free_ void *p = NULL; ++ struct statvfs vfs; + ssize_t n; + ++ if (fstatvfs(fd, &vfs) < 0) { ++ log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m"); ++ return; ++ } ++ ++ /* Refuse operating on file systems that have ++ * mandatory locking enabled, see: ++ * ++ * https://github.com/systemd/systemd/issues/1822 ++ */ ++ if (vfs.f_flag & ST_MANDLOCK) { ++ log_error("Received file descriptor from file system with mandatory locking enable, refusing."); ++ return; ++ } ++ ++ /* Make the fd non-blocking. On regular files this has ++ * the effect of bypassing mandatory locking. Of ++ * course, this should normally not be necessary given ++ * the check above, but let's better be safe than ++ * sorry, after all NFS is pretty confusing regarding ++ * file system flags, and we better don't trust it, ++ * and so is SMB. */ ++ r = fd_nonblock(fd, true); ++ if (r < 0) { ++ log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m"); ++ return; ++ } ++ + /* The file is not sealed, we can't map the file here, since + * clients might then truncate it and trigger a SIGBUS for + * us. So let's stupidly read it */ diff --git a/SOURCES/0553-udev-builtin-keyboard-move-fetching-the-device-node-.patch b/SOURCES/0553-udev-builtin-keyboard-move-fetching-the-device-node-.patch new file mode 100644 index 0000000..cf020a9 --- /dev/null +++ b/SOURCES/0553-udev-builtin-keyboard-move-fetching-the-device-node-.patch @@ -0,0 +1,52 @@ +From 7d6891da40f2f5cfbc5bf02b6a58dc49c1577373 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Fri, 20 Mar 2015 12:48:24 +1000 +Subject: [PATCH] udev: builtin-keyboard: move fetching the device node up + +No point parsing the properties if we can't get the devnode to apply them +later. Plus, this makes future additions easier to slot in. + +(cherry picked from commit 753bd5c7ede5e74c21221fcf59de3ce320d6722d) + +Resolves: #1500119 +--- + src/udev/udev-builtin-keyboard.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c +index d8ee4cbb6..bde7bf07f 100644 +--- a/src/udev/udev-builtin-keyboard.c ++++ b/src/udev/udev-builtin-keyboard.c +@@ -75,6 +75,13 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + unsigned map_count = 0; + unsigned release[1024]; + unsigned release_count = 0; ++ const char *node; ++ ++ node = udev_device_get_devnode(dev); ++ if (!node) { ++ log_error("Error, no device node for '%s'", udev_device_get_syspath(dev)); ++ return EXIT_FAILURE; ++ } + + udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) { + const char *key; +@@ -128,17 +135,10 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + } + + if (map_count > 0 || release_count > 0) { +- const char *node; + int fd; + unsigned i; + +- node = udev_device_get_devnode(dev); +- if (!node) { +- log_error("Error, no device node for '%s'", udev_device_get_syspath(dev)); +- return EXIT_FAILURE; +- } +- +- fd = open(udev_device_get_devnode(dev), O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); ++ fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + if (fd < 0) { + log_error_errno(errno, "Error, opening device '%s': %m", node); + return EXIT_FAILURE; diff --git a/SOURCES/0554-udev-builtin-keyboard-immediately-EVIOCSKEYCODE-when.patch b/SOURCES/0554-udev-builtin-keyboard-immediately-EVIOCSKEYCODE-when.patch new file mode 100644 index 0000000..129e378 --- /dev/null +++ b/SOURCES/0554-udev-builtin-keyboard-immediately-EVIOCSKEYCODE-when.patch @@ -0,0 +1,90 @@ +From 4f9b03c28555799f8672b905323bf6d1f95eb13f Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Fri, 20 Mar 2015 12:52:46 +1000 +Subject: [PATCH] udev: builtin-keyboard: immediately EVIOCSKEYCODE when we + have a pair + +Rather than building a map and looping through the map, immediately call the +ioctl when we have a successfully parsed property. + +This has a side-effect: before the maximum number of ioctls was limited to the +size of the map (1024), now it is unlimited. + +(cherry picked from commit cfba2656e3b4a9c5e03db4ec0a8f76c3762d35a8) + +Resolves: #1500119 +--- + src/udev/udev-builtin-keyboard.c | 45 ++++++++++++++++------------------------ + 1 file changed, 18 insertions(+), 27 deletions(-) + +diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c +index bde7bf07f..515edd45c 100644 +--- a/src/udev/udev-builtin-keyboard.c ++++ b/src/udev/udev-builtin-keyboard.c +@@ -71,10 +71,10 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + struct { + unsigned scan; + unsigned key; +- } map[1024]; +- unsigned map_count = 0; ++ } map; + unsigned release[1024]; + unsigned release_count = 0; ++ _cleanup_close_ int fd = -1; + const char *node; + + node = udev_device_get_devnode(dev); +@@ -128,37 +128,28 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + } + } + +- map[map_count].scan = scancode; +- map[map_count].key = keycode_num; +- if (map_count < ELEMENTSOF(map)-1) +- map_count++; +- } +- +- if (map_count > 0 || release_count > 0) { +- int fd; +- unsigned i; +- +- fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); +- if (fd < 0) { +- log_error_errno(errno, "Error, opening device '%s': %m", node); +- return EXIT_FAILURE; ++ if (fd == -1) { ++ fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); ++ if (fd < 0) { ++ log_error_errno(errno, "Error, opening device '%s': %m", node); ++ return EXIT_FAILURE; ++ } + } + +- /* install list of map codes */ +- for (i = 0; i < map_count; i++) { +- log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)", +- map[i].scan, map[i].scan, map[i].key, map[i].key); +- if (ioctl(fd, EVIOCSKEYCODE, &map[i]) < 0) +- log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map[i].scan, map[i].key); +- } ++ map.scan = scancode; ++ map.key = keycode_num; + +- /* install list of force-release codes */ +- if (release_count > 0) +- install_force_release(dev, release, release_count); ++ log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)", ++ map.scan, map.scan, map.key, map.key); + +- close(fd); ++ if (ioctl(fd, EVIOCSKEYCODE, &map) < 0) ++ log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map.scan, map.key); + } + ++ /* install list of force-release codes */ ++ if (release_count > 0) ++ install_force_release(dev, release, release_count); ++ + return EXIT_SUCCESS; + } + diff --git a/SOURCES/0555-udev-builtin-keyboard-move-actual-key-mapping-to-a-h.patch b/SOURCES/0555-udev-builtin-keyboard-move-actual-key-mapping-to-a-h.patch new file mode 100644 index 0000000..6750c02 --- /dev/null +++ b/SOURCES/0555-udev-builtin-keyboard-move-actual-key-mapping-to-a-h.patch @@ -0,0 +1,114 @@ +From 3b4e03492fd157ab87ea625a8ad1eb91cef7396b Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Fri, 20 Mar 2015 13:17:20 +1000 +Subject: [PATCH] udev: builtin-keyboard: move actual key mapping to a helper + function + +No changes in the mapping, but previously we opened the device only on +successful parsing. Now we open the mapping as soon as we have a value that +looks interesting. Since errors are supposed to be the exception, not the +rule, this is probably fine. + +(cherry picked from commit c9a8e34094733018727677fee44be2c2952224c0) + +Resolves: #1500119 +--- + src/udev/udev-builtin-keyboard.c | 58 +++++++++++++++++++++++----------------- + 1 file changed, 33 insertions(+), 25 deletions(-) + +diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c +index 515edd45c..f33401790 100644 +--- a/src/udev/udev-builtin-keyboard.c ++++ b/src/udev/udev-builtin-keyboard.c +@@ -66,12 +66,41 @@ static int install_force_release(struct udev_device *dev, const unsigned *releas + return ret; + } + +-static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) { +- struct udev_list_entry *entry; ++static void map_keycode(int fd, const char *devnode, int scancode, const char *keycode) ++{ + struct { + unsigned scan; + unsigned key; + } map; ++ char *endptr; ++ const struct key *k; ++ unsigned keycode_num; ++ ++ /* translate identifier to key code */ ++ k = keyboard_lookup_key(keycode, strlen(keycode)); ++ if (k) { ++ keycode_num = k->id; ++ } else { ++ /* check if it's a numeric code already */ ++ keycode_num = strtoul(keycode, &endptr, 0); ++ if (endptr[0] !='\0') { ++ log_error("Error, unknown key identifier '%s'", keycode); ++ return; ++ } ++ } ++ ++ map.scan = scancode; ++ map.key = keycode_num; ++ ++ log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)", ++ map.scan, map.scan, map.key, map.key); ++ ++ if (ioctl(fd, EVIOCSKEYCODE, &map) < 0) ++ log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode, map.scan, map.key); ++} ++ ++static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) { ++ struct udev_list_entry *entry; + unsigned release[1024]; + unsigned release_count = 0; + _cleanup_close_ int fd = -1; +@@ -85,10 +114,9 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + + udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) { + const char *key; +- unsigned scancode, keycode_num; + char *endptr; ++ unsigned scancode; + const char *keycode; +- const struct key *k; + + key = udev_list_entry_get_name(entry); + if (!startswith(key, "KEYBOARD_KEY_")) +@@ -115,19 +143,6 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + continue; + } + +- /* translate identifier to key code */ +- k = keyboard_lookup_key(keycode, strlen(keycode)); +- if (k) { +- keycode_num = k->id; +- } else { +- /* check if it's a numeric code already */ +- keycode_num = strtoul(keycode, &endptr, 0); +- if (endptr[0] !='\0') { +- log_error("Error, unknown key identifier '%s'", keycode); +- continue; +- } +- } +- + if (fd == -1) { + fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + if (fd < 0) { +@@ -136,14 +151,7 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + } + } + +- map.scan = scancode; +- map.key = keycode_num; +- +- log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)", +- map.scan, map.scan, map.key, map.key); +- +- if (ioctl(fd, EVIOCSKEYCODE, &map) < 0) +- log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map.scan, map.key); ++ map_keycode(fd, node, scancode, keycode); + } + + /* install list of force-release codes */ diff --git a/SOURCES/0556-udev-builtin-keyboard-invert-a-condition.patch b/SOURCES/0556-udev-builtin-keyboard-invert-a-condition.patch new file mode 100644 index 0000000..f809524 --- /dev/null +++ b/SOURCES/0556-udev-builtin-keyboard-invert-a-condition.patch @@ -0,0 +1,90 @@ +From a347fcea7ab1648cfa28b4fbb903ae95b879b86e Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Fri, 20 Mar 2015 14:00:31 +1000 +Subject: [PATCH] udev: builtin-keyboard: invert a condition + +No functional changes, just to make the next patch easier to review + +(cherry picked from commit 8a0fd83cf03547653a195582ba004d2ff69dfbd0) + +Resolves: #1500119 +--- + src/udev/udev-builtin-keyboard.c | 56 ++++++++++++++++++++-------------------- + 1 file changed, 28 insertions(+), 28 deletions(-) + +diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c +index f33401790..86f4018ef 100644 +--- a/src/udev/udev-builtin-keyboard.c ++++ b/src/udev/udev-builtin-keyboard.c +@@ -115,43 +115,43 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) { + const char *key; + char *endptr; +- unsigned scancode; +- const char *keycode; + + key = udev_list_entry_get_name(entry); +- if (!startswith(key, "KEYBOARD_KEY_")) +- continue; +- +- /* KEYBOARD_KEY_= */ +- scancode = strtoul(key + 13, &endptr, 16); +- if (endptr[0] != '\0') { +- log_error("Error, unable to parse scan code from '%s'", key); +- continue; +- } ++ if (startswith(key, "KEYBOARD_KEY_")) { ++ const char *keycode; ++ unsigned scancode; ++ ++ /* KEYBOARD_KEY_= */ ++ scancode = strtoul(key + 13, &endptr, 16); ++ if (endptr[0] != '\0') { ++ log_error("Error, unable to parse scan code from '%s'", key); ++ continue; ++ } + +- keycode = udev_list_entry_get_value(entry); ++ keycode = udev_list_entry_get_value(entry); + +- /* a leading '!' needs a force-release entry */ +- if (keycode[0] == '!') { +- keycode++; ++ /* a leading '!' needs a force-release entry */ ++ if (keycode[0] == '!') { ++ keycode++; + +- release[release_count] = scancode; +- if (release_count < ELEMENTSOF(release)-1) +- release_count++; ++ release[release_count] = scancode; ++ if (release_count < ELEMENTSOF(release)-1) ++ release_count++; + +- if (keycode[0] == '\0') +- continue; +- } ++ if (keycode[0] == '\0') ++ continue; ++ } + +- if (fd == -1) { +- fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); +- if (fd < 0) { +- log_error_errno(errno, "Error, opening device '%s': %m", node); +- return EXIT_FAILURE; ++ if (fd == -1) { ++ fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); ++ if (fd < 0) { ++ log_error_errno(errno, "Error, opening device '%s': %m", node); ++ return EXIT_FAILURE; ++ } + } +- } + +- map_keycode(fd, node, scancode, keycode); ++ map_keycode(fd, node, scancode, keycode); ++ } + } + + /* install list of force-release codes */ diff --git a/SOURCES/0557-udev-builtin-keyboard-add-support-for-EVDEV_ABS_.patch b/SOURCES/0557-udev-builtin-keyboard-add-support-for-EVDEV_ABS_.patch new file mode 100644 index 0000000..9736e98 --- /dev/null +++ b/SOURCES/0557-udev-builtin-keyboard-add-support-for-EVDEV_ABS_.patch @@ -0,0 +1,240 @@ +From e6682abae36dcfe8a093686a3bd67b3568157c35 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Thu, 19 Mar 2015 14:19:58 +1000 +Subject: [PATCH] udev: builtin-keyboard: add support for EVDEV_ABS_* + +Parse properties in the form +EVDEV_ABS_00="::::" + +and apply them to the kernel device. Future processes that open that device +will see the updated EV_ABS range. + +This is particularly useful for touchpads that don't provide a resolution in +the kernel driver but can be fixed up through hwdb entries (e.g. bcm5974). + +All values in the property are optional, e.g. a string of "::45" is valid to +set the resolution to 45. + +The order intentionally orders resolution before fuzz and flat despite it +being the last element in the absinfo struct. The use-case for setting +fuzz/flat is almost non-existent, resolution is probably the most common case +we'll need. + +To avoid multiple hwdb invocations for the same device, replace the +hwdb "keyboard:" prefix with "evdev:" and drop the separate 60-keyboard.rules +file. The new 60-evdev.rules is called for all event nodes +anyway, we don't need a separate rules file and second callout to the hwdb +builtin. + +(cherry picked from commit 51c0c2869845a058268d54c3111d55d0dd485704) + +Changes to the upstream commit: +- 60-keyboard.rules is left in place, the 60-keyboard.hwdb is left + unmodified. This avoids any potential breakage from user-installed hwdb + files that are triggered by that rule. + +Conflicts: + hwdb/60-keyboard.hwdb + rules/60-keyboard.rules + +Resolves: #1500119 +--- + Makefile.am | 2 + + hwdb/60-evdev.hwdb | 37 +++++++++++++++++ + rules/60-evdev.rules | 14 +++++++ + src/udev/udev-builtin-keyboard.c | 86 ++++++++++++++++++++++++++++++++++++++-- + 4 files changed, 135 insertions(+), 4 deletions(-) + create mode 100644 hwdb/60-evdev.hwdb + create mode 100644 rules/60-evdev.rules + +diff --git a/Makefile.am b/Makefile.am +index a1ebf5cb0..13c93f485 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3499,6 +3499,7 @@ dist_udevrules_DATA += \ + rules/42-usb-hid-pm.rules \ + rules/50-udev-default.rules \ + rules/60-drm.rules \ ++ rules/60-evdev.rules \ + rules/60-keyboard.rules \ + rules/60-persistent-storage-tape.rules \ + rules/60-persistent-serial.rules \ +@@ -3702,6 +3703,7 @@ dist_udevhwdb_DATA = \ + hwdb/20-acpi-vendor.hwdb \ + hwdb/20-OUI.hwdb \ + hwdb/20-net-ifname.hwdb \ ++ hwdb/60-evdev.hwdb \ + hwdb/60-keyboard.hwdb \ + hwdb/70-mouse.hwdb \ + hwdb/70-touchpad.hwdb +diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb +new file mode 100644 +index 000000000..ad2d09e72 +--- /dev/null ++++ b/hwdb/60-evdev.hwdb +@@ -0,0 +1,37 @@ ++# This file is part of systemd. ++# ++# The lookup keys are composed in: ++# 60-evdev.rules ++# ++# Note: The format of the "evdev:" prefix match key is a ++# contract between the rules file and the hardware data, it might ++# change in later revisions to support more or better matches, it ++# is not necessarily expected to be a stable ABI. ++# ++# Match string formats: ++# evdev: ++# evdev:name::dmi: ++# ++# To add local entries, create a new file ++# /etc/udev/hwdb.d/61-evdev-local.hwdb ++# and add your rules there. To load the new rules execute (as root): ++# udevadm hwdb --update ++# udevadm trigger /dev/input/eventXX ++# where /dev/input/eventXX is the device in question. If in ++# doubt, simply use /dev/input/event* to reload all input rules. ++# ++# If your changes are generally applicable, open a bug report on ++# http://bugs.freedesktop.org/enter_bug.cgi?product=systemd ++# and include your new rules, a description of the device, and the ++# output of ++# udevadm info /dev/input/eventXX ++# (or /dev/input/event*). ++# ++# Allowed properties are: ++# EVDEV_ABS_=:::: ++# ++# where is the hexadecimal EV_ABS code as listed in linux/input.h ++# and min, max, res, fuzz, flat are the decimal values to the respective ++# fields of the struct input_absinfo as listed in linux/input.h. ++# If a field is missing the field will be left as-is. Not all fields need to ++# be present. e.g. ::45 sets the resolution to 45 units/mm. +diff --git a/rules/60-evdev.rules b/rules/60-evdev.rules +new file mode 100644 +index 000000000..67308ad23 +--- /dev/null ++++ b/rules/60-evdev.rules +@@ -0,0 +1,14 @@ ++# do not edit this file, it will be overwritten on update ++ ++ACTION=="remove", GOTO="evdev_end" ++KERNEL!="event*", GOTO="evdev_end" ++ ++# skip later rules when we find something for this input device ++IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=evdev:", \ ++ RUN{builtin}+="keyboard", GOTO="evdev_end" ++ ++# device matching the input device name and the machine's DMI data ++KERNELS=="input*", IMPORT{builtin}="hwdb 'evdev:name:$attr{name}:$attr{[dmi/id]modalias}'", \ ++ RUN{builtin}+="keyboard", GOTO="evdev_end" ++ ++LABEL="evdev_end" +diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c +index 86f4018ef..eaa21abf6 100644 +--- a/src/udev/udev-builtin-keyboard.c ++++ b/src/udev/udev-builtin-keyboard.c +@@ -99,6 +99,69 @@ static void map_keycode(int fd, const char *devnode, int scancode, const char *k + log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode, map.scan, map.key); + } + ++static inline char* parse_token(const char *current, int32_t *val_out) { ++ char *next; ++ int32_t val; ++ ++ if (!current) ++ return NULL; ++ ++ val = strtol(current, &next, 0); ++ if (*next && *next != ':') ++ return NULL; ++ ++ if (next != current) ++ *val_out = val; ++ ++ if (*next) ++ next++; ++ ++ return next; ++} ++ ++static void override_abs(int fd, const char *devnode, ++ unsigned evcode, const char *value) { ++ struct input_absinfo absinfo; ++ int rc; ++ char *next; ++ ++ rc = ioctl(fd, EVIOCGABS(evcode), &absinfo); ++ if (rc < 0) { ++ log_error_errno(errno, "Error, unable to EVIOCGABS device '%s'", ++ devnode); ++ return; ++ } ++ ++ next = parse_token(value, &absinfo.minimum); ++ next = parse_token(next, &absinfo.maximum); ++ next = parse_token(next, &absinfo.resolution); ++ next = parse_token(next, &absinfo.fuzz); ++ next = parse_token(next, &absinfo.flat); ++ if (!next) { ++ log_error("Error, unable to parse EV_ABS override '%s' for '%s'\n", ++ value, devnode); ++ return; ++ } ++ ++ log_debug("keyboard: override %x with %d/%d/%d/%d/%d", evcode, ++ absinfo.minimum, absinfo.maximum, absinfo.resolution, ++ absinfo.fuzz, absinfo.flat); ++ rc = ioctl(fd, EVIOCSABS(evcode), &absinfo); ++ if (rc < 0) ++ log_error_errno(errno, "Error, unable to update device '%s'", ++ devnode); ++} ++ ++static int open_device(const char *devnode) { ++ int fd; ++ ++ fd = open(devnode, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); ++ if (fd < 0) ++ log_error_errno(errno, "Error, opening device '%s': %m", devnode); ++ ++ return fd < 0 ? -errno : fd; ++} ++ + static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) { + struct udev_list_entry *entry; + unsigned release[1024]; +@@ -143,14 +206,29 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo + } + + if (fd == -1) { +- fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); +- if (fd < 0) { +- log_error_errno(errno, "Error, opening device '%s': %m", node); ++ fd = open_device(node); ++ if (fd < 0) + return EXIT_FAILURE; +- } + } + + map_keycode(fd, node, scancode, keycode); ++ } else if (startswith(key, "EVDEV_ABS_")) { ++ unsigned evcode; ++ ++ /* EVDEV_ABS_=:::: */ ++ evcode = strtoul(key + 10, &endptr, 16); ++ if (endptr[0] != '\0') { ++ log_error("Error, unable to parse EV_ABS code from '%s'", key); ++ continue; ++ } ++ ++ if (fd == -1) { ++ fd = open_device(node); ++ if (fd < 0) ++ return EXIT_FAILURE; ++ } ++ ++ override_abs(fd, node, evcode, udev_list_entry_get_value(entry)); + } + } + diff --git a/SOURCES/0558-hwdb-sync-60-evdev.hwdb-from-systemd-v235.patch b/SOURCES/0558-hwdb-sync-60-evdev.hwdb-from-systemd-v235.patch new file mode 100644 index 0000000..5bb7108 --- /dev/null +++ b/SOURCES/0558-hwdb-sync-60-evdev.hwdb-from-systemd-v235.patch @@ -0,0 +1,436 @@ +From 525d254a21daa1ddd6634a465596299121fd0470 Mon Sep 17 00:00:00 2001 +From: Peter Hutterer +Date: Tue, 10 Oct 2017 10:08:16 +1000 +Subject: [PATCH] hwdb: sync 60-evdev.hwdb from systemd v235 + +Resolves: rhbz#1500119 +--- + hwdb/60-evdev.hwdb | 407 ++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 400 insertions(+), 7 deletions(-) + +diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb +index ad2d09e72..f688ef269 100644 +--- a/hwdb/60-evdev.hwdb ++++ b/hwdb/60-evdev.hwdb +@@ -15,17 +15,17 @@ + # To add local entries, create a new file + # /etc/udev/hwdb.d/61-evdev-local.hwdb + # and add your rules there. To load the new rules execute (as root): +-# udevadm hwdb --update ++# systemd-hwdb update + # udevadm trigger /dev/input/eventXX + # where /dev/input/eventXX is the device in question. If in + # doubt, simply use /dev/input/event* to reload all input rules. + # +-# If your changes are generally applicable, open a bug report on +-# http://bugs.freedesktop.org/enter_bug.cgi?product=systemd +-# and include your new rules, a description of the device, and the +-# output of +-# udevadm info /dev/input/eventXX +-# (or /dev/input/event*). ++# If your changes are generally applicable, preferably send them as a pull ++# request to ++# https://github.com/systemd/systemd ++# or create a bug report on https://github.com/systemd/systemd/issues and ++# include your new rules, a description of the device, and the output of ++# udevadm info /dev/input/eventXX. + # + # Allowed properties are: + # EVDEV_ABS_=:::: +@@ -35,3 +35,396 @@ + # fields of the struct input_absinfo as listed in linux/input.h. + # If a field is missing the field will be left as-is. Not all fields need to + # be present. e.g. ::45 sets the resolution to 45 units/mm. ++ ++# ++# Sort by brand, model ++ ++######################################### ++# Apple ++######################################### ++ ++# Macbook2,1 (late 2006), single-button touchpad ++evdev:input:b0003v05ACp021B* ++# Macbook4,1 ++evdev:input:b0003v05ACp0229* ++ EVDEV_ABS_00=256:1471:12 ++ EVDEV_ABS_01=256:831:12 ++ ++# Macbook5,1 (unibody), aka wellspring3 ++evdev:input:b0003v05ACp0236* ++evdev:input:b0003v05ACp0237* ++evdev:input:b0003v05ACp0238* ++ EVDEV_ABS_00=::92 ++ EVDEV_ABS_01=::90 ++ EVDEV_ABS_35=::92 ++ EVDEV_ABS_36=::90 ++ ++# Macbook8 (unibody, March 2011) ++evdev:input:b0003v05ACp0245* ++evdev:input:b0003v05ACp0246* ++evdev:input:b0003v05ACp0247* ++ EVDEV_ABS_00=::92 ++ EVDEV_ABS_01=::91 ++ EVDEV_ABS_35=::92 ++ EVDEV_ABS_36=::91 ++ ++# Macbook8,2 (unibody) ++evdev:input:b0003v05ACp0252* ++evdev:input:b0003v05ACp0253* ++evdev:input:b0003v05ACp0254* ++ EVDEV_ABS_00=::94 ++ EVDEV_ABS_01=::92 ++ EVDEV_ABS_35=::94 ++ EVDEV_ABS_36=::92 ++ ++# MacbookPro10,1 (unibody, June 2012) ++evdev:input:b0003v05ACp0262* ++evdev:input:b0003v05ACp0263* ++evdev:input:b0003v05ACp0264* ++# MacbookPro10,2 (unibody, October 2012) ++evdev:input:b0003v05ACp0259* ++evdev:input:b0003v05ACp025A* ++evdev:input:b0003v05ACp025B* ++ EVDEV_ABS_00=::94 ++ EVDEV_ABS_01=::92 ++ EVDEV_ABS_35=::94 ++ EVDEV_ABS_36=::92 ++ ++######################################### ++# ASUS ++######################################### ++ ++# Asus VivoBook E402SA ++evdev:name:Elan Touchpad:dmi:*svnASUSTeKCOMPUTERINC.:pnE402SA* ++ EVDEV_ABS_00=::29 ++ EVDEV_ABS_01=::29 ++ EVDEV_ABS_35=::29 ++ EVDEV_ABS_36=::29 ++ ++# Asus K52JT ++evdev:name:ETPS/2 Elantech Touchpad:dmi:bvn*:bvr*:bd*:svnASUSTeKComputerInc.:pnK52JT:* ++ EVDEV_ABS_00=::18 ++ EVDEV_ABS_01=::16 ++ EVDEV_ABS_35=::18 ++ EVDEV_ABS_36=::16 ++ ++# Asus X550CC and S550CB ++evdev:name:ETPS/2 Elantech Touchpad:dmi:*:svnASUSTeKCOMPUTERINC.:pn?550C?:* ++ EVDEV_ABS_00=::31 ++ EVDEV_ABS_01=::30 ++ EVDEV_ABS_35=::31 ++ EVDEV_ABS_36=::30 ++ ++# Asus UX301L ++evdev:name:Elan Touchpad:dmi:*:svnASUSTeKCOMPUTERINC.:pnUX301LAA:* ++ EVDEV_ABS_00=::30 ++ EVDEV_ABS_01=::29 ++ EVDEV_ABS_35=::30 ++ EVDEV_ABS_36=::29 ++ ++# Asus UX305 ++evdev:name:Elan Touchpad:dmi:*:svnASUSTeKCOMPUTERINC.:pnUX305UA:* ++ EVDEV_ABS_00=0:3097:32 ++ EVDEV_ABS_01=0:2119:33 ++ EVDEV_ABS_35=0:3097:32 ++ EVDEV_ABS_36=0:2119:33 ++ ++######################################### ++# Dell ++######################################### ++ ++# Dell Vostro 1510 ++evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510* ++ EVDEV_ABS_00=::14 ++ EVDEV_ABS_01=::18 ++ ++# Dell Inspiron N5040 ++evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnInspironN5040* ++ EVDEV_ABS_00=25:2000:22 ++ EVDEV_ABS_01=0:1351:28 ++ EVDEV_ABS_35=25:2000:22 ++ EVDEV_ABS_36=0:1351:28 ++ ++# Dell Latitude E6220 ++evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6220* ++ EVDEV_ABS_00=76:1815:22 ++ EVDEV_ABS_01=131:1330:30 ++ EVDEV_ABS_35=76:1815:22 ++ EVDEV_ABS_36=131:1330:30 ++ ++# Dell Latitude E6320 ++evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6320* ++ EVDEV_ABS_00=79:1841:22 ++ EVDEV_ABS_01=140:1325:29 ++ EVDEV_ABS_35=79:1841:22 ++ EVDEV_ABS_36=140:1325:29 ++ ++# Dell Latitude E7470 ++evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7470* ++ EVDEV_ABS_00=39:5856:59 ++ EVDEV_ABS_01=10:1532:29 ++ EVDEV_ABS_35=39:5856:59 ++ EVDEV_ABS_36=10:1532:29 ++ ++# Dell Precision 5510 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnPrecision5510* ++ EVDEV_ABS_00=::42 ++ EVDEV_ABS_01=::43 ++ EVDEV_ABS_35=::42 ++ EVDEV_ABS_36=::43 ++ ++# Dell Precision M4700 ++evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*svnDellInc.:pnPrecisionM4700* ++ EVDEV_ABS_00=0:1960:24 ++ EVDEV_ABS_01=113:1436:30 ++ EVDEV_ABS_35=0:1960:24 ++ EVDEV_ABS_36=113:1436:30 ++ ++# Dell XPS15 9550 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPS159550* ++ EVDEV_ABS_00=::41 ++ EVDEV_ABS_01=::43 ++ EVDEV_ABS_35=::41 ++ EVDEV_ABS_36=::43 ++ ++# Dell XPS M1530 ++evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPSM1530* ++ EVDEV_ABS_00=85:947:15 ++ EVDEV_ABS_01=154:726:18 ++ ++##### ++# Sun ++##### ++ ++# Fujitsu Component - USB Touch Panel ++evdev:input:b0003v0430p0530* ++ EVDEV_ABS_00=0:4096:16 ++ EVDEV_ABS_01=0:4096:16 ++ ++######################################### ++# Google ++######################################### ++ ++# Chromebook Pixel (2015) - Samus ++evdev:name:Atmel maXTouch Touch*:dmi:bvn*:bvr*:bd*:svnGOOGLE:pnSamus* ++ EVDEV_ABS_00=::10 ++ EVDEV_ABS_01=::10 ++ EVDEV_ABS_35=::10 ++ EVDEV_ABS_36=::10 ++ ++######################################### ++# HP ++######################################### ++ ++# HP Pavilion dm4 ++evdev:name:SynPS/2 Synaptics TouchPad*:dmi:*svnHewlett-Packard:pnHPPaviliondm4* ++ EVDEV_ABS_00=1360:5563:47 ++ EVDEV_ABS_01=1269:4618:61 ++ EVDEV_ABS_35=1360:5563:47 ++ EVDEV_ABS_36=1269:4618:61 ++ ++# HP Pavilion dv7 ++evdev:name:SynPS/2 Synaptics TouchPad*:dmi:*svnHewlett-Packard:pnHPPaviliondv7* ++ EVDEV_ABS_00=1068:5805:44 ++ EVDEV_ABS_01=1197:4890:57 ++ EVDEV_ABS_35=1068:5805:44 ++ EVDEV_ABS_36=1197:4890:57 ++ ++# HP Spectre ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:i*svnHP:pnHPSpectreNotebook* ++ EVDEV_ABS_00=1205:5691:47 ++ EVDEV_ABS_01=1083:4808:65 ++ EVDEV_ABS_35=1205:5691:47 ++ EVDEV_ABS_36=1083:4808:65 ++ ++######################################### ++# Lenovo ++######################################### ++ ++# Lenovo B590 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrLenovoB590* ++ EVDEV_ABS_00=1243:5759:48 ++ EVDEV_ABS_01=1130:4832:65 ++ EVDEV_ABS_35=1243:5759:48 ++ EVDEV_ABS_36=1130:4832:65 ++ ++# Lenovo E530 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:pn*ThinkPadEdgeE530* ++ EVDEV_ABS_00=1241:5703:49 ++ EVDEV_ABS_01=1105:4820:68 ++ EVDEV_ABS_35=1241:5703:49 ++ EVDEV_ABS_36=1105:4820:68 ++ ++# Lenovo L430 ++evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnLENOVO*:pvrThinkPadL430* ++ EVDEV_ABS_00=19:2197:29 ++ EVDEV_ABS_01=12:1151:25 ++ EVDEV_ABS_35=19:2197:29 ++ EVDEV_ABS_36=12:1151:25 ++ ++# Lenovo P50 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*P50* ++ EVDEV_ABS_00=::44 ++ EVDEV_ABS_01=::67 ++ EVDEV_ABS_35=::44 ++ EVDEV_ABS_36=::67 ++ ++# Lenovo *40 series ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPad??40:* ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPad??40?:* ++ EVDEV_ABS_00=::41 ++ EVDEV_ABS_01=::37 ++ EVDEV_ABS_35=::41 ++ EVDEV_ABS_36=::37 ++ ++# Lenovo ThinkPad T430 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadT430* ++ EVDEV_ABS_00=1250:5631:58 ++ EVDEV_ABS_01=1309:4826:78 ++ EVDEV_ABS_35=1250:5631:58 ++ EVDEV_ABS_36=1309:4826:78 ++ ++# Lenovo Thinkpad Carbon X1 4th gen. and X1 Yoga 1st gen. ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX1Carbon4th* ++ EVDEV_ABS_00=1262:5679:44 ++ EVDEV_ABS_01=1101:4824:65 ++ EVDEV_ABS_35=1262:5679:44 ++ EVDEV_ABS_36=1101:4824:65 ++ ++# Lenovo Thinkpad Carbon X1 5th gen. ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pvrThinkPadX1Carbon5th* ++ EVDEV_ABS_00=::44 ++ EVDEV_ABS_01=::65 ++ EVDEV_ABS_35=::44 ++ EVDEV_ABS_36=::65 ++ ++# Lenovo Thinkpad Carbon X1 5th gen. (rmi4) ++evdev:name:Synaptics TM3289-002:dmi:*svnLENOVO*:pvrThinkPadX1Carbon5th* ++ EVDEV_ABS_00=::19 ++ EVDEV_ABS_01=::19 ++ EVDEV_ABS_35=::19 ++ EVDEV_ABS_36=::19 ++ ++# Lenovo T460 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T460* ++ EVDEV_ABS_00=1266:5677:44 ++ EVDEV_ABS_01=1093:4832:65 ++ EVDEV_ABS_35=1266:5677:44 ++ EVDEV_ABS_36=1093:4832:65 ++ ++# Lenovo T510 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T510* ++ EVDEV_ABS_00=778:6239:72 ++ EVDEV_ABS_01=841:5330:100 ++ EVDEV_ABS_35=778:6239:72 ++ EVDEV_ABS_36=841:5330:100 ++ ++# Lenovo V360 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrLenovoV360* ++ EVDEV_ABS_00=1243:5927:60 ++ EVDEV_ABS_01=902:5330:108 ++ ++# Lenovo W530 ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadW530* ++ EVDEV_ABS_00=1250:5631:59 ++ EVDEV_ABS_01=1205:4834:81 ++ EVDEV_ABS_35=1250:5631:59 ++ EVDEV_ABS_36=1205:4834:81 ++ ++# Lenovo X220 series ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadX220* ++ EVDEV_ABS_00=1316:5627:58 ++ EVDEV_ABS_01=1355:4826:81 ++ EVDEV_ABS_35=1316:5627:58 ++ EVDEV_ABS_36=1355:4826:81 ++ ++# Lenovo X230 series ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*X230* ++ EVDEV_ABS_01=::100 ++ EVDEV_ABS_36=::100 ++ ++# Lenovo Y700-14ISK ++evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoideapadY700-14ISK* ++ EVDEV_ABS_00=::27 ++ EVDEV_ABS_01=::29 ++ EVDEV_ABS_35=::27 ++ EVDEV_ABS_36=::29 ++ ++# Lenovo Ideapad 500S-13ISK ++evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoideapad500S-13ISK* ++ EVDEV_ABS_00=125:3955:37 ++ EVDEV_ABS_01=104:1959:27 ++ EVDEV_ABS_35=125:3954:37 ++ EVDEV_ABS_36=104:1959:27 ++ ++# Lenovo Yoga 500-14ISK ++evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoYoga500-14ISK* ++ EVDEV_ABS_00=124:3955:36 ++ EVDEV_ABS_01=103:1959:26 ++ EVDEV_ABS_35=124:3955:36 ++ EVDEV_ABS_36=103:1959:26 ++ ++# Lenovo Flex 3 15-inch ++evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnLENOVO*:pvrFlex3-15* ++ EVDEV_ABS_00=::38 ++ EVDEV_ABS_01=::28 ++ EVDEV_ABS_35=::38 ++ EVDEV_ABS_36=::28 ++ ++######################################### ++# Samsung ++######################################### ++ ++# Samsung 305V4 ++evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn305V4A/305V5A* ++ EVDEV_ABS_00=0:2480:28 ++ EVDEV_ABS_01=0:1116:24 ++ EVDEV_ABS_35=0:2480:28 ++ EVDEV_ABS_36=0:1116:24 ++ ++# Samsung 880Z5E ++evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn870Z5E/880Z5E/680Z5E* ++ EVDEV_ABS_00=::30 ++ EVDEV_ABS_01=::29 ++ EVDEV_ABS_35=::30 ++ EVDEV_ABS_36=::29 ++ ++######################################### ++# System76 ++######################################### ++ ++# GalagoPro 2 (galp2) ++evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnSystem76:pnGalagoPro:pvrgalp2:* ++ EVDEV_ABS_00=1238:5747:50 ++ EVDEV_ABS_01=901:4900:83 ++ EVDEV_ABS_35=1238:5747:50 ++ EVDEV_ABS_36=901:4900:83 ++ ++######################################### ++# Toshiba ++######################################### ++ ++# Toshiba Tecra M11 ++evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*svnTOSHIBA:pnTECRAM11* ++ EVDEV_ABS_00=90:962:11 ++ EVDEV_ABS_01=51:681:14 ++ ++######################################### ++# Razer ++######################################### ++ ++# Razer Blade Stealth (2016) ++evdev:name:Synaptics TM2438-005:dmi:*svnRazer:pnBladeStealth* ++ EVDEV_ABS_00=0:4064:29 ++ EVDEV_ABS_01=0:2405:37 ++ EVDEV_ABS_35=0:4064:29 ++ EVDEV_ABS_36=0:2405:37 ++ ++######################################### ++# Waltop ++######################################### ++ ++# WALTOP International Corp. Slim Tablet ++evdev:input:b0003v172Fp0031* ++ EVDEV_ABS_00=0:10000:400 ++ EVDEV_ABS_01=0:6250:400 diff --git a/SOURCES/0559-journal-ensure-open-journals-from-find_journal-3973.patch b/SOURCES/0559-journal-ensure-open-journals-from-find_journal-3973.patch new file mode 100644 index 0000000..8f6023f --- /dev/null +++ b/SOURCES/0559-journal-ensure-open-journals-from-find_journal-3973.patch @@ -0,0 +1,266 @@ +From b36c31ddc2f3427ea2a1f700db08d8e104e4110a Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 5 Oct 2017 11:26:21 +0200 +Subject: [PATCH] journal: ensure open journals from find_journal() (#3973) + +If journals get into a closed state like when rotate fails due to +ENOSPC, when space is made available it currently goes unnoticed leaving +the journals in a closed state indefinitely. + +By calling system_journal_open() on entry to find_journal() we ensure +the journal has been opened/created if possible. + +Also moved system_journal_open() up to after open_journal(), before +find_journal(). + +Fixes https://github.com/systemd/systemd/issues/3968 + +(cherry picked from commit 105bdb46b4ac7eb658a2f27727216591d0bfe267) + +Resolves: #1493846 +--- + src/journal/journald-server.c | 217 ++++++++++++++++++++++-------------------- + 1 file changed, 114 insertions(+), 103 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index c1358e1e9..96e7d6156 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -239,6 +239,109 @@ finish: + #endif + } + ++static bool flushed_flag_is_set(void) { ++ return access("/run/systemd/journal/flushed", F_OK) >= 0; ++} ++ ++static int system_journal_open(Server *s, bool flush_requested) { ++ int r; ++ char *fn; ++ sd_id128_t machine; ++ char ids[33]; ++ ++ r = sd_id128_get_machine(&machine); ++ if (r < 0) ++ return log_error_errno(r, "Failed to get machine id: %m"); ++ ++ sd_id128_to_string(machine, ids); ++ ++ if (!s->system_journal && ++ IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) && ++ (flush_requested || flushed_flag_is_set())) { ++ ++ /* If in auto mode: first try to create the machine ++ * path, but not the prefix. ++ * ++ * If in persistent mode: create /var/log/journal and ++ * the machine path */ ++ ++ if (s->storage == STORAGE_PERSISTENT) ++ (void) mkdir_p("/var/log/journal/", 0755); ++ ++ fn = strjoina("/var/log/journal/", ids); ++ (void) mkdir(fn, 0755); ++ ++ fn = strjoina(fn, "/system.journal"); ++ r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal); ++ ++ if (r >= 0) ++ server_fix_perms(s, s->system_journal, 0); ++ else if (r < 0) { ++ if (r != -ENOENT && r != -EROFS) ++ log_warning_errno(r, "Failed to open system journal: %m"); ++ ++ r = 0; ++ } ++ ++ /* If the runtime journal is open, and we're post-flush, we're ++ * recovering from a failed system journal rotate (ENOSPC) ++ * for which the runtime journal was reopened. ++ * ++ * Perform an implicit flush to var, leaving the runtime ++ * journal closed, now that the system journal is back. ++ */ ++ if (!flush_requested) ++ (void) server_flush_to_var(s, true); ++ } ++ ++ if (!s->runtime_journal && ++ (s->storage != STORAGE_NONE)) { ++ ++ fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL); ++ if (!fn) ++ return -ENOMEM; ++ ++ if (s->system_journal) { ++ ++ /* Try to open the runtime journal, but only ++ * if it already exists, so that we can flush ++ * it into the system journal */ ++ ++ r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); ++ free(fn); ++ ++ if (r < 0) { ++ if (r != -ENOENT) ++ log_warning_errno(r, "Failed to open runtime journal: %m"); ++ ++ r = 0; ++ } ++ ++ } else { ++ ++ /* OK, we really need the runtime journal, so create ++ * it if necessary. */ ++ ++ (void) mkdir("/run/log", 0755); ++ (void) mkdir("/run/log/journal", 0755); ++ (void) mkdir_parents(fn, 0750); ++ ++ r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); ++ free(fn); ++ ++ if (r < 0) ++ return log_error_errno(r, "Failed to open runtime journal: %m"); ++ } ++ ++ if (s->runtime_journal) ++ server_fix_perms(s, s->runtime_journal, 0); ++ } ++ ++ available_space(s, true); ++ ++ return r; ++} ++ + static JournalFile* find_journal(Server *s, uid_t uid) { + _cleanup_free_ char *p = NULL; + int r; +@@ -247,6 +350,17 @@ static JournalFile* find_journal(Server *s, uid_t uid) { + + assert(s); + ++ /* A rotate that fails to create the new journal (ENOSPC) leaves the ++ * rotated journal as NULL. Unless we revisit opening, even after ++ * space is made available we'll continue to return NULL indefinitely. ++ * ++ * system_journal_open() is a noop if the journals are already open, so ++ * we can just call it here to recover from failed rotates (or anything ++ * else that's left the journals as NULL). ++ * ++ * Fixes https://github.com/systemd/systemd/issues/3968 */ ++ (void) system_journal_open(s, false); ++ + /* We split up user logs only on /var, not on /run. If the + * runtime file is open, we write to it exclusively, in order + * to guarantee proper order as soon as we flush /run to +@@ -917,109 +1031,6 @@ finish: + dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid); + } + +-static bool flushed_flag_is_set(void) { +- return access("/run/systemd/journal/flushed", F_OK) >= 0; +-} +- +-static int system_journal_open(Server *s, bool flush_requested) { +- int r; +- char *fn; +- sd_id128_t machine; +- char ids[33]; +- +- r = sd_id128_get_machine(&machine); +- if (r < 0) +- return log_error_errno(r, "Failed to get machine id: %m"); +- +- sd_id128_to_string(machine, ids); +- +- if (!s->system_journal && +- IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) && +- (flush_requested || flushed_flag_is_set())) { +- +- /* If in auto mode: first try to create the machine +- * path, but not the prefix. +- * +- * If in persistent mode: create /var/log/journal and +- * the machine path */ +- +- if (s->storage == STORAGE_PERSISTENT) +- (void) mkdir_p("/var/log/journal/", 0755); +- +- fn = strjoina("/var/log/journal/", ids); +- (void) mkdir(fn, 0755); +- +- fn = strjoina(fn, "/system.journal"); +- r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal); +- +- if (r >= 0) +- server_fix_perms(s, s->system_journal, 0); +- else if (r < 0) { +- if (r != -ENOENT && r != -EROFS) +- log_warning_errno(r, "Failed to open system journal: %m"); +- +- r = 0; +- } +- +- /* If the runtime journal is open, and we're post-flush, we're +- * recovering from a failed system journal rotate (ENOSPC) +- * for which the runtime journal was reopened. +- * +- * Perform an implicit flush to var, leaving the runtime +- * journal closed, now that the system journal is back. +- */ +- if (!flush_requested) +- (void) server_flush_to_var(s, true); +- } +- +- if (!s->runtime_journal && +- (s->storage != STORAGE_NONE)) { +- +- fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL); +- if (!fn) +- return -ENOMEM; +- +- if (s->system_journal) { +- +- /* Try to open the runtime journal, but only +- * if it already exists, so that we can flush +- * it into the system journal */ +- +- r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); +- free(fn); +- +- if (r < 0) { +- if (r != -ENOENT) +- log_warning_errno(r, "Failed to open runtime journal: %m"); +- +- r = 0; +- } +- +- } else { +- +- /* OK, we really need the runtime journal, so create +- * it if necessary. */ +- +- (void) mkdir("/run/log", 0755); +- (void) mkdir("/run/log/journal", 0755); +- (void) mkdir_parents(fn, 0750); +- +- r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); +- free(fn); +- +- if (r < 0) +- return log_error_errno(r, "Failed to open runtime journal: %m"); +- } +- +- if (s->runtime_journal) +- server_fix_perms(s, s->runtime_journal, 0); +- } +- +- available_space(s, true); +- +- return r; +-} +- + int server_flush_to_var(Server *s, bool require_flag_file) { + sd_id128_t machine; + sd_journal *j = NULL; diff --git a/SOURCES/0560-journal-only-check-available-space-when-journal-is-o.patch b/SOURCES/0560-journal-only-check-available-space-when-journal-is-o.patch new file mode 100644 index 0000000..3fce2ef --- /dev/null +++ b/SOURCES/0560-journal-only-check-available-space-when-journal-is-o.patch @@ -0,0 +1,69 @@ +From 3511688b336ee36f200d2ade5e3bdc01de9c503e Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Mon, 9 Oct 2017 12:47:21 +0200 +Subject: [PATCH] journal: only check available space when journal is open + +RHEL-only + +Related: #1493846 +--- + src/journal/journald-server.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 96e7d6156..f6f8c30eb 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -253,12 +253,12 @@ static int system_journal_open(Server *s, bool flush_requested) { + if (r < 0) + return log_error_errno(r, "Failed to get machine id: %m"); + +- sd_id128_to_string(machine, ids); +- + if (!s->system_journal && + IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) && + (flush_requested || flushed_flag_is_set())) { + ++ sd_id128_to_string(machine, ids); ++ + /* If in auto mode: first try to create the machine + * path, but not the prefix. + * +@@ -274,9 +274,10 @@ static int system_journal_open(Server *s, bool flush_requested) { + fn = strjoina(fn, "/system.journal"); + r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal); + +- if (r >= 0) ++ if (r >= 0) { + server_fix_perms(s, s->system_journal, 0); +- else if (r < 0) { ++ available_space(s, true); ++ } else if (r < 0) { + if (r != -ENOENT && r != -EROFS) + log_warning_errno(r, "Failed to open system journal: %m"); + +@@ -297,6 +298,8 @@ static int system_journal_open(Server *s, bool flush_requested) { + if (!s->runtime_journal && + (s->storage != STORAGE_NONE)) { + ++ sd_id128_to_string(machine, ids); ++ + fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL); + if (!fn) + return -ENOMEM; +@@ -333,12 +336,12 @@ static int system_journal_open(Server *s, bool flush_requested) { + return log_error_errno(r, "Failed to open runtime journal: %m"); + } + +- if (s->runtime_journal) ++ if (s->runtime_journal) { + server_fix_perms(s, s->runtime_journal, 0); ++ available_space(s, true); ++ } + } + +- available_space(s, true); +- + return r; + } + diff --git a/SOURCES/0561-automount-if-an-automount-unit-is-masked-don-t-react.patch b/SOURCES/0561-automount-if-an-automount-unit-is-masked-don-t-react.patch new file mode 100644 index 0000000..afaf168 --- /dev/null +++ b/SOURCES/0561-automount-if-an-automount-unit-is-masked-don-t-react.patch @@ -0,0 +1,158 @@ +From 85eeadc898d2c0f8b7524982c84b88b01a5dcb89 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 1 Mar 2017 04:03:48 +0100 +Subject: [PATCH] automount: if an automount unit is masked, don't react to + activation anymore (#5445) + +Otherwise we'll hit an assert sooner or later. + +This requires us to initialize ->where even if we come back in "masked" +mode, as otherwise we don't know how to operate on the automount and +detach it. + +Fixes: #5441 +(cherry picked from commit e350ca3f1ecb6672b74cd25d09ef23c7b309aa5a) + +Resolves: #1498318 +--- + src/core/automount.c | 74 +++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 50 insertions(+), 24 deletions(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index 4e066613d..20a5de8ca 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -106,18 +106,18 @@ static void unmount_autofs(Automount *a) { + if (a->pipe_fd < 0) + return; + +- automount_send_ready(a, a->tokens, -EHOSTDOWN); +- automount_send_ready(a, a->expire_tokens, -EHOSTDOWN); +- + a->pipe_event_source = sd_event_source_unref(a->pipe_event_source); + a->pipe_fd = safe_close(a->pipe_fd); + +- /* If we reload/reexecute things we keep the mount point +- * around */ +- if (a->where && +- (UNIT(a)->manager->exit_code != MANAGER_RELOAD && +- UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) +- repeat_unmount(a->where); ++ /* If we reload/reexecute things we keep the mount point around */ ++ if (!IN_SET(UNIT(a)->manager->exit_code, MANAGER_RELOAD, MANAGER_REEXECUTE)) { ++ ++ automount_send_ready(a, a->tokens, -EHOSTDOWN); ++ automount_send_ready(a, a->expire_tokens, -EHOSTDOWN); ++ ++ if (a->where) ++ repeat_unmount(a->where); ++ } + } + + static void automount_done(Unit *u) { +@@ -193,6 +193,20 @@ static int automount_verify(Automount *a) { + return 0; + } + ++static int automount_set_where(Automount *a) { ++ assert(a); ++ ++ if (a->where) ++ return 0; ++ ++ a->where = unit_name_to_path(UNIT(a)->id); ++ if (!a->where) ++ return -ENOMEM; ++ ++ path_kill_slashes(a->where); ++ return 1; ++} ++ + static int automount_load(Unit *u) { + Automount *a = AUTOMOUNT(u); + int r; +@@ -208,13 +222,9 @@ static int automount_load(Unit *u) { + if (u->load_state == UNIT_LOADED) { + Unit *x; + +- if (!a->where) { +- a->where = unit_name_to_path(u->id); +- if (!a->where) +- return -ENOMEM; +- } +- +- path_kill_slashes(a->where); ++ r = automount_set_where(a); ++ if (r < 0) ++ return r; + + r = unit_load_related_unit(u, ".mount", &x); + if (r < 0) +@@ -259,6 +269,8 @@ static void automount_set_state(Automount *a, AutomountState state) { + unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true); + } + ++static int automount_start_expire(Automount *a); ++ + static int automount_coldplug(Unit *u, Hashmap *deferred_work) { + Automount *a = AUTOMOUNT(u); + int r; +@@ -266,20 +278,30 @@ static int automount_coldplug(Unit *u, Hashmap *deferred_work) { + assert(a); + assert(a->state == AUTOMOUNT_DEAD); + +- if (a->deserialized_state != a->state) { ++ if (a->deserialized_state == a->state) ++ return 0; ++ ++ if (IN_SET(a->deserialized_state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING)) { ++ ++ r = automount_set_where(a); ++ if (r < 0) ++ return r; + + r = open_dev_autofs(u->manager); + if (r < 0) + return r; + +- if (a->deserialized_state == AUTOMOUNT_WAITING || +- a->deserialized_state == AUTOMOUNT_RUNNING) { ++ assert(a->pipe_fd >= 0); + +- assert(a->pipe_fd >= 0); ++ r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u); ++ if (r < 0) ++ return r; + +- r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u); ++ (void) sd_event_source_set_description(a->pipe_event_source, "automount-io"); ++ if (a->deserialized_state == AUTOMOUNT_RUNNING) { ++ r = automount_start_expire(a); + if (r < 0) +- return r; ++ log_unit_warning_errno(UNIT(a)->id, r, "Failed to start expiration timer, ignoring: %m"); + } + + automount_set_state(a, a->deserialized_state); +@@ -636,8 +658,6 @@ static void *expire_thread(void *p) { + return NULL; + } + +-static int automount_start_expire(Automount *a); +- + static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) { + Automount *a = AUTOMOUNT(userdata); + _cleanup_(expire_data_freep) struct expire_data *data = NULL; +@@ -699,6 +719,12 @@ static void automount_enter_runnning(Automount *a) { + + assert(a); + ++ /* If the user masked our unit in the meantime, fail */ ++ if (UNIT(a)->load_state != UNIT_LOADED) { ++ log_unit_error(UNIT(a)->id, "Suppressing automount event since unit is no longer loaded."); ++ goto fail; ++ } ++ + /* We don't take mount requests anymore if we are supposed to + * shut down anyway */ + if (unit_stop_pending(UNIT(a))) { diff --git a/SOURCES/0562-units-add-Install-section-to-remote-cryptsetup.targe.patch b/SOURCES/0562-units-add-Install-section-to-remote-cryptsetup.targe.patch new file mode 100644 index 0000000..a8693a1 --- /dev/null +++ b/SOURCES/0562-units-add-Install-section-to-remote-cryptsetup.targe.patch @@ -0,0 +1,44 @@ +From 923299bbe6aa2c22a2592dcbcae722f273e7a5dd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 12 Oct 2017 22:13:03 +0200 +Subject: [PATCH] units: add [Install] section to remote-cryptsetup.target + +This makes this target the same as remote-fs.target in this regard. In practice +it probably doesn't make that much difference, because all encrypted devices +that are part of remote-fs.target (marked with _netdev) will be used for mount +points, so they will be pulled in anyway individually, but with this change any +such device will be configured, even if it is not pulled by any other unit. + +Cherry-picked from: 8f462b074eb9830d6d5029f70c9010ce50e68357 +Resolves: #1477757 +--- + system-preset/90-systemd.preset | 1 + + units/remote-cryptsetup.target | 6 ++++++ + 2 files changed, 7 insertions(+) + +diff --git a/system-preset/90-systemd.preset b/system-preset/90-systemd.preset +index 24963f062..a011ec67a 100644 +--- a/system-preset/90-systemd.preset ++++ b/system-preset/90-systemd.preset +@@ -9,6 +9,7 @@ + # generally follow a default-off policy. + + enable remote-fs.target ++enable remote-cryptsetup.target + enable machines.target + + enable getty@.service +diff --git a/units/remote-cryptsetup.target b/units/remote-cryptsetup.target +index 60943bd1c..c306d521f 100644 +--- a/units/remote-cryptsetup.target ++++ b/units/remote-cryptsetup.target +@@ -8,3 +8,9 @@ + [Unit] + Description=Remote Encrypted Volumes + Documentation=man:systemd.special(7) ++After=remote-cryptsetup-pre.target ++DefaultDependencies=no ++Conflicts=shutdown.target ++ ++[Install] ++WantedBy=multi-user.target diff --git a/SOURCES/0563-units-replace-remote-cryptsetup-pre.target-with-remo.patch b/SOURCES/0563-units-replace-remote-cryptsetup-pre.target-with-remo.patch new file mode 100644 index 0000000..6ef7b47 --- /dev/null +++ b/SOURCES/0563-units-replace-remote-cryptsetup-pre.target-with-remo.patch @@ -0,0 +1,152 @@ +From 0d13caa0714c32af45165310e93f62c965f45b01 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 12 Oct 2017 22:34:54 +0200 +Subject: [PATCH] units: replace remote-cryptsetup-pre.target with + remote-fs-pre.target + +remote-cryptsetup-pre.target was designed as an active unit (that pulls in +network-online.target), the opposite of remote-fs-pre.target (a passive unit, +with individual provider services ordering itself before it and pulling it in, +for example iscsi.service and nfs-client.target). + +To make remote-cryptsetup-pre.target really work, those services should be +ordered before it too. But this would require updates to all those services, +not just changes from systemd side. + +But the requirements for remote-fs-pre.target and remote-cryptset-pre.target +are fairly similar (e.g. iscsi devices can certainly be used for both), so +let's reuse remote-fs-pre.target also for remote cryptsetup units. This loses +a bit of flexibility, but does away with the requirement for various provider +services to know about remote-cryptsetup-pre.target. + +Cherry-picked from: a0dd209763f9e67054ee322a2dfd52bccf345c2e +Resolves: #1477757 +--- + Makefile.am | 3 +-- + man/crypttab.xml | 2 +- + man/systemd.special.xml | 20 ++++---------------- + src/cryptsetup/cryptsetup-generator.c | 2 +- + units/remote-cryptsetup-pre.target | 15 --------------- + units/remote-cryptsetup.target | 2 +- + 6 files changed, 8 insertions(+), 36 deletions(-) + delete mode 100644 units/remote-cryptsetup-pre.target + +diff --git a/Makefile.am b/Makefile.am +index 13c93f485..f06bc29c2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4864,8 +4864,7 @@ systemgenerator_PROGRAMS += \ + dist_systemunit_DATA += \ + units/cryptsetup.target \ + units/cryptsetup-pre.target \ +- units/remote-cryptsetup.target \ +- units/remote-cryptsetup-pre.target ++ units/remote-cryptsetup.target + + systemd_cryptsetup_SOURCES = \ + src/cryptsetup/cryptsetup.c +diff --git a/man/crypttab.xml b/man/crypttab.xml +index 7085a1623..a9197ab40 100644 +--- a/man/crypttab.xml ++++ b/man/crypttab.xml +@@ -196,7 +196,7 @@ + started after the network is available, similarly to + systemd.mount5 + units marked with . The service unit to set up this device +- will be ordered between remote-cryptsetup-pre.target and ++ will be ordered between remote-fs-pre.target and + remote-cryptsetup.target, instead of + cryptsetup-pre.target and + cryptsetup.target. +diff --git a/man/systemd.special.xml b/man/systemd.special.xml +index 5529d3bf7..e04f08bd3 100644 +--- a/man/systemd.special.xml ++++ b/man/systemd.special.xml +@@ -81,7 +81,6 @@ + poweroff.target, + printer.target, + reboot.target, +- remote-cryptsetup-pre.target, + remote-cryptsetup.target, + remote-fs.target, + remote-fs-pre.target, +@@ -406,18 +405,6 @@ + this target unit, for compatibility with SysV. + + +- +- remote-cryptsetup-pre.target +- +- This target unit is automatically ordered before all cryptsetup devices +- marked with the . It can be used to execute additional +- units before such devices are set up. +- +- It is ordered after network.target and +- network-online.target, and also pulls the latter in as a +- Wants= dependency. +- +- + + remote-cryptsetup.target + +@@ -768,9 +755,10 @@ + remote-fs-pre.target + + This target unit is automatically ordered before all +- remote mount point units (see above). It can be used to run +- certain units before the remote mounts are established. Note +- that this unit is generally not part of the initial ++ mount point units (see above) and cryptsetup devices ++ marked with the . It can be used to run ++ certain units before remote encrypted devices and mounts are established. ++ Note that this unit is generally not part of the initial + transaction, unless the unit that wants to be ordered before + all remote mounts pulls it in via a + Wants= type dependency. If the unit wants +diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c +index 49dc8f14b..82a280d86 100644 +--- a/src/cryptsetup/cryptsetup-generator.c ++++ b/src/cryptsetup/cryptsetup-generator.c +@@ -114,7 +114,7 @@ static int create_disk( + "IgnoreOnIsolate=true\n" + "After=systemd-readahead-collect.service systemd-readahead-replay.service\n" + "After=%s\n", +- netdev ? "remote-cryptsetup-pre.target" : "cryptsetup-pre.target"); ++ netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target"); + + if (!nofail) + fprintf(f, +diff --git a/units/remote-cryptsetup-pre.target b/units/remote-cryptsetup-pre.target +deleted file mode 100644 +index a375e6188..000000000 +--- a/units/remote-cryptsetup-pre.target ++++ /dev/null +@@ -1,15 +0,0 @@ +-# This file is part of systemd. +-# +-# systemd is free software; you can redistribute it and/or modify it +-# under the terms of the GNU Lesser General Public License as published by +-# the Free Software Foundation; either version 2.1 of the License, or +-# (at your option) any later version. +- +-[Unit] +-Description=Remote Encrypted Volumes (Pre) +-Documentation=man:systemd.special(7) +-RefuseManualStart=yes +-Before=remote-cryptsetup.target +- +-After=network.target network-online.target +-Wants=network-online.target +diff --git a/units/remote-cryptsetup.target b/units/remote-cryptsetup.target +index c306d521f..d485b0672 100644 +--- a/units/remote-cryptsetup.target ++++ b/units/remote-cryptsetup.target +@@ -8,7 +8,7 @@ + [Unit] + Description=Remote Encrypted Volumes + Documentation=man:systemd.special(7) +-After=remote-cryptsetup-pre.target ++After=remote-fs-pre.target + DefaultDependencies=no + Conflicts=shutdown.target + diff --git a/SOURCES/0564-man-add-a-note-about-_netdev-usage.patch b/SOURCES/0564-man-add-a-note-about-_netdev-usage.patch new file mode 100644 index 0000000..c72084c --- /dev/null +++ b/SOURCES/0564-man-add-a-note-about-_netdev-usage.patch @@ -0,0 +1,41 @@ +From 3608a654d9d9c4f9d75454e5fe190ef938e9a4f4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Thu, 12 Oct 2017 22:43:58 +0200 +Subject: [PATCH] man: add a note about _netdev usage + +Cherry-picked from: 288c26165e0ff71857394f360f42432bc808556f +Resolves: #1477757 +--- + man/crypttab.xml | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/man/crypttab.xml b/man/crypttab.xml +index a9197ab40..e4ecab3dc 100644 +--- a/man/crypttab.xml ++++ b/man/crypttab.xml +@@ -199,7 +199,16 @@ + will be ordered between remote-fs-pre.target and + remote-cryptsetup.target, instead of + cryptsetup-pre.target and +- cryptsetup.target. ++ cryptsetup.target. ++ ++ Hint: if this device is used for a mount point that is specified in ++ fstab5, ++ the option should also be used for the mount ++ point. Otherwise, a dependency loop might be created where the mount point ++ will be pulled in by local-fs.target, while the ++ service to configure the network is usually only started after ++ the local file system has been mounted. ++ + + + +@@ -396,6 +405,7 @@ hidden /mnt/tc_hidden /dev/null tcrypt-hidden,tcrypt-keyfile=/etc/keyfil + systemd1, + systemd-cryptsetup@.service8, + systemd-cryptsetup-generator8, ++ fstab5, + cryptsetup8, + mkswap8, + mke2fs8 diff --git a/SOURCES/0565-units-make-remote-cryptsetup.target-also-after-crypt.patch b/SOURCES/0565-units-make-remote-cryptsetup.target-also-after-crypt.patch new file mode 100644 index 0000000..5fb3090 --- /dev/null +++ b/SOURCES/0565-units-make-remote-cryptsetup.target-also-after-crypt.patch @@ -0,0 +1,28 @@ +From d3b747ccbd34fd11298429787e67429af9c06dbb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Wed, 18 Oct 2017 15:14:46 +0200 +Subject: [PATCH] units: make remote-cryptsetup.target also after + cryptsetup-pre.target + +This way people can order units before cryptsetup-pre.target and +have them run before any cryptsetup-related stuff. + +Cherry-picked from: a0e030f53bad355be1084a0475eb30aae20e3e43 +Resolves: #1477757 +--- + units/remote-cryptsetup.target | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/units/remote-cryptsetup.target b/units/remote-cryptsetup.target +index d485b0672..ac4e1b71d 100644 +--- a/units/remote-cryptsetup.target ++++ b/units/remote-cryptsetup.target +@@ -8,7 +8,7 @@ + [Unit] + Description=Remote Encrypted Volumes + Documentation=man:systemd.special(7) +-After=remote-fs-pre.target ++After=remote-fs-pre.target cryptsetup-pre.target + DefaultDependencies=no + Conflicts=shutdown.target + diff --git a/SOURCES/0566-cryptsetup-generator-use-after-free.patch b/SOURCES/0566-cryptsetup-generator-use-after-free.patch new file mode 100644 index 0000000..9cdfb0c --- /dev/null +++ b/SOURCES/0566-cryptsetup-generator-use-after-free.patch @@ -0,0 +1,28 @@ +From ae554d506040559c2dbf972ecf4a33be4fb6d869 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 31 Oct 2017 12:59:02 +0100 +Subject: [PATCH] cryptsetup-generator: use after free + +rhel-only + +Related: #1477757 +--- + src/cryptsetup/cryptsetup-generator.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c +index 82a280d86..c387e2104 100644 +--- a/src/cryptsetup/cryptsetup-generator.c ++++ b/src/cryptsetup/cryptsetup-generator.c +@@ -214,10 +214,8 @@ static int create_disk( + return log_oom(); + + mkdir_parents_label(to, 0755); +- if (symlink(from, to) < 0) { +- free(to); ++ if (symlink(from, to) < 0) + return log_error_errno(errno, "Failed to create symlink %s: %m", to); +- } + } + + free(to); diff --git a/SOURCES/0567-manager-fix-connecting-to-bus-when-dbus-is-actually-.patch b/SOURCES/0567-manager-fix-connecting-to-bus-when-dbus-is-actually-.patch new file mode 100644 index 0000000..d6ee4d4 --- /dev/null +++ b/SOURCES/0567-manager-fix-connecting-to-bus-when-dbus-is-actually-.patch @@ -0,0 +1,34 @@ +From d46ca2a3ed881bc9324ebd9da0a66af1133d43a7 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 1 Nov 2017 02:25:48 -0700 +Subject: [PATCH] manager: fix connecting to bus when dbus is actually around + (#7205) + +manager_connect_bus() is called *before* manager_coldplug(). As a last +thing in service_coldplug() we set service state to +s->deserialized_state, and thus before we do that all services are +inactive and try_connect always evaluates to false. To fix that we must +look at deserialized state instead of current unit state. + +Fixes #7146 + +(cherry picked from commit 41dfa61d35c51a584437481d20541d5c3ccfa93d) + +Related: #1465737 +--- + 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 041fac46b..47b09e1e9 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -809,7 +809,7 @@ static int manager_connect_bus(Manager *m, bool reexecuting) { + u = manager_get_unit(m, SPECIAL_DBUS_SERVICE); + + try_bus_connect = +- (u && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) && ++ (u && SERVICE(u)->deserialized_state == SERVICE_RUNNING) && + (reexecuting || + (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"))); + diff --git a/SOURCES/0568-journal-remote-make-url-option-support-arbitrary-url.patch b/SOURCES/0568-journal-remote-make-url-option-support-arbitrary-url.patch new file mode 100644 index 0000000..59537ff --- /dev/null +++ b/SOURCES/0568-journal-remote-make-url-option-support-arbitrary-url.patch @@ -0,0 +1,40 @@ +From 70c096e5ae7bb7b415c82ee6cc177ac2d557feff Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 24 Jan 2016 15:45:47 +0900 +Subject: [PATCH] journal-remote: make --url option support arbitrary url + +Currently, --url option supports the only form like http(s)://some.host:19531. +This commit adds support to call systemd-journal-remote as follwos: +systemd-journal-remote --url='http://some.host:19531' +systemd-journal-remote --url='http://some.host:19531/' +systemd-journal-remote --url='http://some.host:19531/entries' +systemd-journal-remote --url='http://some.host:19531/entries?boot&follow' +The first three example result the same and retrieve all entries. +The last example retrieves only current boot entries and wait new events. + +Cherry-picked from: b68f6b0a794f9e6cb6457a0ac55041c4e7b1a5cb +Resolves: #1505385 +--- + src/journal-remote/journal-remote.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c +index 4fac55cc9..a455fb6bd 100644 +--- a/src/journal-remote/journal-remote.c ++++ b/src/journal-remote/journal-remote.c +@@ -894,7 +894,14 @@ static int remoteserver_init(RemoteServer *s, + if (arg_url) { + const char *url, *hostname; + +- url = strjoina(arg_url, "/entries"); ++ if (!strstr(arg_url, "/entries")) { ++ if (endswith(arg_url, "/")) ++ url = strjoina(arg_url, "entries"); ++ else ++ url = strjoina(arg_url, "/entries"); ++ } ++ else ++ url = strdupa(arg_url); + + if (arg_getter) { + log_info("Spawning getter %s...", url); diff --git a/SOURCES/0569-journald-make-maximum-size-of-stream-log-lines-confi.patch b/SOURCES/0569-journald-make-maximum-size-of-stream-log-lines-confi.patch new file mode 100644 index 0000000..a238169 --- /dev/null +++ b/SOURCES/0569-journald-make-maximum-size-of-stream-log-lines-confi.patch @@ -0,0 +1,525 @@ +From 32244f8d21a3e06f6519c47234289da696f6b151 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Sun, 8 Oct 2017 09:05:59 +0200 +Subject: [PATCH] journald: make maximum size of stream log lines configurable + and bump it to 48K (#6838) + +This adds a new setting LineMax= to journald.conf, and sets it by +default to 48K. When we convert stream-based stdout/stderr logging into +record-based log entries, read up to the specified amount of bytes +before forcing a line-break. + +This also makes three related changes: + +- When a NUL byte is read we'll not recognize this as alternative line + break, instead of silently dropping everything after it. (see #4863) + +- The reason for a line-break is now encoded in the log record, if it + wasn't a plain newline. Specifically, we distuingish "nul", + "line-max" and "eof", for line breaks due to NUL byte, due to the + maximum line length as configured with LineMax= or due to end of + stream. This data is stored in the new implicit _LINE_BREAK= field. + It's not synthesized for plain \n line breaks. + +- A randomized 128bit ID is assigned to each log stream. + +With these three changes in place it's (mostly) possible to reconstruct +the original byte streams from log data, as (most) of the context of +the conversion from the byte stream to log records is saved now. (So, +the only bits we still drop are empty lines. Which might be something to +look into in a future change, and which is outside of the scope of this +work) + +Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=86465 +See: #4863 +Replaces: #4875 + +(cherry picked from commit ec20fe5ffb8a00469bab209fff6c069bb93c6db2) + +Resolves: #1442262 + +[msekleta: I had to manually rewrite upstream commit, because git +did very poor job merging old and new code and identified a lot of merge +conflicts in a code that was totally unrelated.] +--- + man/journald.conf.xml | 18 ++++++ + man/systemd.journal-fields.xml | 22 ++++++++ + src/journal/journald-gperf.gperf | 1 + + src/journal/journald-server.c | 68 +++++++++++++++++++++++ + src/journal/journald-server.h | 3 + + src/journal/journald-stream.c | 116 ++++++++++++++++++++++++++++++++------- + src/journal/journald.conf | 1 + + 7 files changed, 209 insertions(+), 20 deletions(-) + +diff --git a/man/journald.conf.xml b/man/journald.conf.xml +index 46a498b67..e2d6a1225 100644 +--- a/man/journald.conf.xml ++++ b/man/journald.conf.xml +@@ -354,6 +354,24 @@ + /dev/console. + + ++ ++ LineMax= ++ ++ The maximum line length to permit when converting stream logs into record logs. When a systemd ++ unit's standard output/error are connected to the journal via a stream socket, the data read is split into ++ individual log records at newline (\n, ASCII 10) and NUL characters. If no such delimiter is ++ read for the specified number of bytes a hard log record boundary is artifically inserted, breaking up overly ++ long lines into multiple log records. Selecting overly large values increases the possible memory usage of the ++ Journal daemon for each stream client, as in the worst case the journal daemon needs to buffer the specified ++ number of bytes in memory before it can flush a new log record to disk. Also note that permitting overly large ++ line maximum line lengths affects compatibility with traditional log protocols as log records might not fit ++ anymore into a single AF_UNIX or AF_INET datagram. Takes a size in ++ bytes. If the value is suffixed with K, M, G or T, the specified size is parsed as Kilobytes, Megabytes, ++ Gigabytes, or Terabytes (with the base 1024), respectively. Defaults to 48K, which is relatively large but ++ still small enough so that log records likely fit into network datagrams along with extra room for ++ metadata. Note that values below 79 are not accepted and will be bumped to 79. ++ ++ + + + +diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml +index 7d6c5c715..a53f8def2 100644 +--- a/man/systemd.journal-fields.xml ++++ b/man/systemd.journal-fields.xml +@@ -311,6 +311,28 @@ + + + ++ ++ _STREAM_ID= ++ ++ Only applies to _TRANSPORT=stream records: specifies a randomized 128bit ID assigned ++ to the stream connection when it was first created. This ID is useful to reconstruct individual log streams ++ from the log records: all log records carrying the same stream ID originate from the same stream. ++ ++ ++ ++ _LINE_BREAK= ++ ++ Only applies to _TRANSPORT=stream records: indicates that the log message in the ++ standard output/error stream was not terminated with a normal newline character (\n, ++ i.e. ASCII 10). Specifically, when set this field is one of (in case the line was ++ terminated by a NUL byte), (in case the maximum log line length was reached, as ++ configured with LineMax= in ++ journald.conf5) or ++ (if this was the last log record of a stream and the stream ended without a final ++ newline character). Note that this record is not generated when a normal newline character was used for ++ marking the log line end. ++ ++ + + + +diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf +index 74554c1c3..73327c10e 100644 +--- a/src/journal/journald-gperf.gperf ++++ b/src/journal/journald-gperf.gperf +@@ -40,3 +40,4 @@ Journal.MaxLevelKMsg, config_parse_log_level, 0, offsetof(Server, max_lev + Journal.MaxLevelConsole, config_parse_log_level, 0, offsetof(Server, max_level_console) + Journal.MaxLevelWall, config_parse_log_level, 0, offsetof(Server, max_level_wall) + Journal.SplitMode, config_parse_split_mode, 0, offsetof(Server, split_mode) ++Journal.LineMax, config_parse_line_max, 0, offsetof(Server, line_max) +\ No newline at end of file +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index f6f8c30eb..daeecd519 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -67,6 +67,10 @@ + + #define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC) + ++/* Pick a good default that is likely to fit into AF_UNIX and AF_INET SOCK_DGRAM datagrams, and even leaves some room +++ * for a bit of additional metadata. */ ++#define DEFAULT_LINE_MAX (48*1024) ++ + static const char* const storage_table[_STORAGE_MAX] = { + [STORAGE_AUTO] = "auto", + [STORAGE_VOLATILE] = "volatile", +@@ -83,9 +87,71 @@ static const char* const split_mode_table[_SPLIT_MAX] = { + [SPLIT_NONE] = "none", + }; + ++ + DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode); + DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting"); + ++int config_parse_line_max( ++ 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) { ++ ++ size_t *sz = data; ++ int r; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ if (isempty(rvalue)) ++ /* Empty assignment means default */ ++ *sz = DEFAULT_LINE_MAX; ++ else { ++ uint64_t v; ++ off_t u; ++ ++ r = parse_size(rvalue, 1024, &u); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse LineMax= value, ignoring: %s", rvalue); ++ return 0; ++ } ++ ++ /* Backport note */ ++ /* Upstream ditched use of off_t however our parse_size implementation still takes off_t* ++ * as an argument. Since we compile with -Werror, we have two choices, either disable sign-compare ++ * warning or do this casting so we don't have to change rest of the code. I think it is ++ * better to do cast here instead of rewriting the code so it deals with off_t instead of ++ * uint64_t. Doing conversion off_t -> uint64_t is something that we should think about. */ ++ v = (uint64_t) u; ++ ++ if (v < 79) { ++ /* Why specify 79 here as minimum line length? Simply, because the most common traditional ++ * terminal size is 80ch, and it might make sense to break one character before the natural ++ * line break would occur on that. */ ++ log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too small, clamping to 79: %s", rvalue); ++ *sz = 79; ++ } else if (v > (uint64_t) (SSIZE_MAX-1)) { ++ /* So, why specify SSIZE_MAX-1 here? Because that's one below the largest size value read() ++ * can return, and we need one extra byte for the trailing NUL byte. Of course IRL such large ++ * memory allocations will fail anyway, hence this limit is mostly theoretical anyway, as we'll ++ * fail much earlier anyway. */ ++ log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too large, clamping to %" PRIu64 ": %s", (uint64_t) (SSIZE_MAX-1), rvalue); ++ *sz = SSIZE_MAX-1; ++ } else ++ *sz = (size_t) v; ++ } ++ ++ return 0; ++} ++ + static uint64_t available_space(Server *s, bool verbose) { + char ids[33]; + _cleanup_free_ char *p = NULL; +@@ -1518,6 +1584,8 @@ int server_init(Server *s) { + s->max_level_console = LOG_INFO; + s->max_level_wall = LOG_EMERG; + ++ s->line_max = DEFAULT_LINE_MAX; ++ + memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics)); + memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics)); + +diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h +index 7a456c2d5..b29410778 100644 +--- a/src/journal/journald-server.h ++++ b/src/journal/journald-server.h +@@ -143,6 +143,8 @@ typedef struct Server { + + /* Cached cgroup root, so that we don't have to query that all the time */ + char *cgroup_root; ++ ++ size_t line_max; + } Server; + + #define N_IOVEC_META_FIELDS 20 +@@ -157,6 +159,7 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format, + const struct ConfigPerfItem* journald_gperf_lookup(const char *key, unsigned length); + + int config_parse_storage(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_line_max(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); + + const char *storage_to_string(Storage s) _const_; + Storage storage_from_string(const char *s) _pure_; +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index 15c9110c0..4d6b7ad18 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -53,6 +53,16 @@ typedef enum StdoutStreamState { + STDOUT_STREAM_RUNNING + } StdoutStreamState; + ++/* The different types of log record terminators: a real \n was read, a NUL character was read, the maximum line length ++ * was reached, or the end of the stream was reached */ ++ ++typedef enum LineBreak { ++ LINE_BREAK_NEWLINE, ++ LINE_BREAK_NUL, ++ LINE_BREAK_LINE_MAX, ++ LINE_BREAK_EOF, ++} LineBreak; ++ + struct StdoutStream { + Server *server; + StdoutStreamState state; +@@ -71,14 +81,17 @@ struct StdoutStream { + + bool fdstore:1; + +- char buffer[LINE_MAX+1]; ++ char *buffer; + size_t length; ++ size_t allocated; + + sd_event_source *event_source; + + char *state_file; + + LIST_FIELDS(StdoutStream, stdout_stream); ++ ++ char id_field[sizeof("_STREAM_ID=")-1 + SD_ID128_STRING_MAX]; + }; + + void stdout_stream_free(StdoutStream *s) { +@@ -101,6 +114,7 @@ void stdout_stream_free(StdoutStream *s) { + free(s->identifier); + free(s->unit_id); + free(s->state_file); ++ free(s->buffer); + + free(s); + } +@@ -151,12 +165,14 @@ static int stdout_stream_save(StdoutStream *s) { + "LEVEL_PREFIX=%i\n" + "FORWARD_TO_SYSLOG=%i\n" + "FORWARD_TO_KMSG=%i\n" +- "FORWARD_TO_CONSOLE=%i\n", ++ "FORWARD_TO_CONSOLE=%i\n" ++ "STREAM_ID=%s\n", + s->priority, + s->level_prefix, + s->forward_to_syslog, + s->forward_to_kmsg, +- s->forward_to_console); ++ s->forward_to_console, ++ s->id_field + strlen("_STREAM_ID=")); + + if (!isempty(s->identifier)) { + _cleanup_free_ char *escaped; +@@ -211,8 +227,8 @@ finish: + return r; + } + +-static int stdout_stream_log(StdoutStream *s, const char *p) { +- struct iovec iovec[N_IOVEC_META_FIELDS + 5]; ++static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_break) { ++ struct iovec iovec[N_IOVEC_META_FIELDS + 7]; + int priority; + char syslog_priority[] = "PRIORITY=\0"; + char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1]; +@@ -245,6 +261,8 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { + + IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout"); + ++ IOVEC_SET_STRING(iovec[n++], s->id_field); ++ + syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority); + IOVEC_SET_STRING(iovec[n++], syslog_priority); + +@@ -259,6 +277,18 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { + IOVEC_SET_STRING(iovec[n++], syslog_identifier); + } + ++ if (line_break != LINE_BREAK_NEWLINE) { ++ const char *c; ++ ++ /* If this log message was generated due to an uncommon line break then mention this in the log ++ * entry */ ++ ++ c = line_break == LINE_BREAK_NUL ? "_LINE_BREAK=nul" : ++ line_break == LINE_BREAK_LINE_MAX ? "_LINE_BREAK=line-max" : ++ "_LINE_BREAK=eof"; ++ IOVEC_SET_STRING(iovec[n++], c); ++ } ++ + message = strappend("MESSAGE=", p); + if (message) + IOVEC_SET_STRING(iovec[n++], message); +@@ -268,12 +298,18 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { + return 0; + } + +-static int stdout_stream_line(StdoutStream *s, char *p) { ++static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) { + int r; + + assert(s); + assert(p); + ++ /* line breaks by NUL, line max length or EOF are not permissible during the negotiation part of the protocol */ ++ if (line_break != LINE_BREAK_NEWLINE && s->state != STDOUT_STREAM_RUNNING) { ++ log_warning("Control protocol line not properly terminated."); ++ return -EINVAL; ++ } ++ + p = strstrip(p); + + switch (s->state) { +@@ -362,7 +398,7 @@ static int stdout_stream_line(StdoutStream *s, char *p) { + return 0; + + case STDOUT_STREAM_RUNNING: +- return stdout_stream_log(s, p); ++ return stdout_stream_log(s, p, line_break); + } + + assert_not_reached("Unknown stream state"); +@@ -378,21 +414,32 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) { + p = s->buffer; + remaining = s->length; + for (;;) { +- char *end; ++ LineBreak line_break; + size_t skip; + +- end = memchr(p, '\n', remaining); +- if (end) +- skip = end - p + 1; +- else if (remaining >= sizeof(s->buffer) - 1) { +- end = p + sizeof(s->buffer) - 1; ++ char *end1, *end2; ++ ++ end1 = memchr(p, '\n', remaining); ++ end2 = memchr(p, 0, end1 ? (size_t) (end1 - p) : remaining); ++ ++ if (end2) { ++ /* We found a NUL terminator */ ++ skip = end2 - p + 1; ++ line_break = LINE_BREAK_NUL; ++ } else if (end1) { ++ /* We found a \n terminator */ ++ *end1 = 0; ++ skip = end1 - p + 1; ++ line_break = LINE_BREAK_NEWLINE; ++ } else if (remaining >= s->server->line_max) { ++ /* Force a line break after the maximum line length */ ++ *(p + s->server->line_max) = 0; + skip = remaining; ++ line_break = LINE_BREAK_LINE_MAX; + } else + break; + +- *end = 0; +- +- r = stdout_stream_line(s, p); ++ r = stdout_stream_line(s, p, line_break); + if (r < 0) + return r; + +@@ -402,7 +449,7 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) { + + if (force_flush && remaining > 0) { + p[remaining] = 0; +- r = stdout_stream_line(s, p); ++ r = stdout_stream_line(s, p, LINE_BREAK_EOF); + if (r < 0) + return r; + +@@ -420,6 +467,7 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) { + + static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + StdoutStream *s = userdata; ++ size_t limit; + ssize_t l; + int r; + +@@ -430,9 +478,20 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, + goto terminate; + } + +- l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length); +- if (l < 0) { ++ /* If the buffer is full already (discounting the extra NUL we need), add room for another 1K */ ++ if (s->length + 1 >= s->allocated) { ++ if (!GREEDY_REALLOC(s->buffer, s->allocated, s->length + 1 + 1024)) { ++ log_oom(); ++ goto terminate; ++ } ++ } ++ ++ /* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also, ++ * always leave room for a terminating NUL we might need to add. */ ++ limit = MIN(s->allocated - 1, s->server->line_max); + ++ l = read(s->fd, s->buffer + s->length, limit - s->length); ++ if (l < 0) { + if (errno == EAGAIN) + return 0; + +@@ -459,11 +518,16 @@ terminate: + + static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { + _cleanup_(stdout_stream_freep) StdoutStream *stream = NULL; ++ sd_id128_t id; + int r; + + assert(s); + assert(fd >= 0); + ++ r = sd_id128_randomize(&id); ++ if (r < 0) ++ return log_error_errno(r, "Failed to generate stream ID: %m"); ++ + stream = new0(StdoutStream, 1); + if (!stream) + return log_oom(); +@@ -471,6 +535,8 @@ static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { + stream->fd = -1; + stream->priority = LOG_INFO; + ++ xsprintf(stream->id_field, "_STREAM_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)); ++ + r = getpeercred(fd, &stream->ucred); + if (r < 0) + return log_error_errno(r, "Failed to determine peer credentials: %m"); +@@ -545,7 +611,8 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) { + *level_prefix = NULL, + *forward_to_syslog = NULL, + *forward_to_kmsg = NULL, +- *forward_to_console = NULL; ++ *forward_to_console = NULL, ++ *stream_id = NULL; + int r; + + assert(stream); +@@ -565,6 +632,7 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) { + "FORWARD_TO_CONSOLE", &forward_to_console, + "IDENTIFIER", &stream->identifier, + "UNIT", &stream->unit_id, ++ "STREAM_ID", &stream_id, + NULL); + if (r < 0) + return log_error_errno(r, "Failed to read: %s", stream->state_file); +@@ -601,6 +669,14 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) { + stream->forward_to_console = r; + } + ++ if (stream_id) { ++ sd_id128_t id; ++ ++ r = sd_id128_from_string(stream_id, &id); ++ if (r >= 0) ++ xsprintf(stream->id_field, "_STREAM_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)); ++ } ++ + return 0; + } + +diff --git a/src/journal/journald.conf b/src/journal/journald.conf +index 3907dfb7f..5355ec2b2 100644 +--- a/src/journal/journald.conf ++++ b/src/journal/journald.conf +@@ -37,3 +37,4 @@ + #MaxLevelKMsg=notice + #MaxLevelConsole=info + #MaxLevelWall=emerg ++#LineMax=48K diff --git a/SOURCES/0570-service-serialize-information-about-currently-execut.patch b/SOURCES/0570-service-serialize-information-about-currently-execut.patch new file mode 100644 index 0000000..08e3ac1 --- /dev/null +++ b/SOURCES/0570-service-serialize-information-about-currently-execut.patch @@ -0,0 +1,304 @@ +From 5aafbcced90ae2a3b418d6fe26c67e820daa8bad Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 23 Jan 2017 17:12:35 +0100 +Subject: [PATCH] service: serialize information about currently executing + command + +Stored information will help us to resume execution after the +daemon-reload. + +This commit implements following scheme, + +* On serialization: + - we count rank of the currently executing command + - we store command type, its rank and command line arguments + +* On deserialization: + - configuration is parsed and loaded + - we deserialize stored data, command type, rank and arguments + - we look at the given rank in the list and if command there has same + arguments then we restore execution at that point + - otherwise we search respective command list and we look for command + that has the same arguments + - if both methods fail we do not do not resume execution at all + +To better illustrate how does above scheme works, please consider +following cases (<<< denotes position where we resume execution after reload) + +; Original unit file +[Service] +ExecStart=/bin/true <<< +ExecStart=/bin/false + +; Swapped commands +; Second command is not going to be executed +[Service] +ExecStart=/bin/false +ExecStart=/bin/true <<< + +; Commands added before +; Same commands are problematic and execution could be restarted at wrong place +[Service] +ExecStart=/bin/foo +ExecStart=/bin/bar +ExecStart=/bin/true <<< +ExecStart=/bin/false + +; Commands added after +; Same commands are not an issue in this case +[Service] +ExecStart=/bin/true <<< +ExecStart=/bin/false +ExecStart=/bin/foo +ExecStart=/bin/bar + +; New commands interleaved with old commands +; Some new commands will be executed while others won't +ExecStart=/bin/foo +ExecStart=/bin/true <<< +ExecStart=/bin/bar +ExecStart=/bin/false + +As you can see, above scheme has some drawbacks. However, in most +cases (we assume that in most common case unit file command list is not +changed while some other command is running for the same unit) it +should cause that systemd does the right thing, which is restoring +execution exactly at the point we were before daemon-reload. + +Fixes #518 + +(cherry picked from commit e266c068b5597e18b2299f9c9d3ee6cf04198c41) + +Resolves: #1404657,#1471230 +--- + src/core/service.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 180 insertions(+), 15 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 3bd6c3338..9ad3a0eb0 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -1950,6 +1950,80 @@ _pure_ static bool service_can_reload(Unit *u) { + return !!s->exec_command[SERVICE_EXEC_RELOAD]; + } + ++static unsigned service_exec_command_index(Unit *u, ServiceExecCommand id, ExecCommand *current) { ++ Service *s = SERVICE(u); ++ unsigned idx = 0; ++ ExecCommand *first, *c; ++ ++ assert(s); ++ ++ first = s->exec_command[id]; ++ ++ /* Figure out where we are in the list by walking back to the beginning */ ++ for (c = current; c != first; c = c->command_prev) ++ idx++; ++ ++ return idx; ++} ++ ++static int service_serialize_exec_command(Unit *u, FILE *f, ExecCommand *command) { ++ Service *s = SERVICE(u); ++ ServiceExecCommand id; ++ unsigned idx; ++ const char *type; ++ char **arg; ++ _cleanup_strv_free_ char **escaped_args = NULL; ++ _cleanup_free_ char *args = NULL, *p = NULL; ++ size_t allocated = 0, length = 0; ++ ++ assert(s); ++ assert(f); ++ ++ if (!command) ++ return 0; ++ ++ if (command == s->control_command) { ++ type = "control"; ++ id = s->control_command_id; ++ } else { ++ type = "main"; ++ id = SERVICE_EXEC_START; ++ } ++ ++ idx = service_exec_command_index(u, id, command); ++ ++ STRV_FOREACH(arg, command->argv) { ++ size_t n; ++ _cleanup_free_ char *e = NULL; ++ ++ e = xescape(*arg, WHITESPACE); ++ if (!e) ++ return -ENOMEM; ++ ++ n = strlen(e); ++ if (!GREEDY_REALLOC(args, allocated, length + 1 + n + 1)) ++ return -ENOMEM; ++ ++ if (length > 0) ++ args[length++] = ' '; ++ ++ memcpy(args + length, e, n); ++ length += n; ++ } ++ ++ if (!GREEDY_REALLOC(args, allocated, length + 1)) ++ return -ENOMEM; ++ args[length++] = 0; ++ ++ p = xescape(command->path, WHITESPACE); ++ if (!p) ++ return -ENOMEM; ++ ++ fprintf(f, "%s-command=%s %u %s %s\n", type, service_exec_command_to_string(id), idx, p, args); ++ ++ return 0; ++} ++ + static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + Service *s = SERVICE(u); + ServiceFDStore *fs; +@@ -1974,12 +2048,8 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + if (s->status_text) + unit_serialize_item(u, f, "status-text", s->status_text); + +- /* FIXME: There's a minor uncleanliness here: if there are +- * multiple commands attached here, we will start from the +- * first one again */ +- if (s->control_command_id >= 0) +- unit_serialize_item(u, f, "control-command", +- service_exec_command_to_string(s->control_command_id)); ++ service_serialize_exec_command(u, f, s->control_command); ++ service_serialize_exec_command(u, f, s->main_command); + + if (s->socket_fd >= 0) { + int copy; +@@ -2035,6 +2105,106 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + return 0; + } + ++static int service_deserialize_exec_command(Unit *u, const char *key, const char *value) { ++ Service *s = SERVICE(u); ++ int r; ++ unsigned idx = 0, i; ++ bool control, found = false; ++ ServiceExecCommand id = _SERVICE_EXEC_COMMAND_INVALID; ++ ExecCommand *command = NULL; ++ _cleanup_free_ char *args = NULL, *path = NULL; ++ _cleanup_strv_free_ char **argv = NULL; ++ ++ enum ExecCommandState { ++ STATE_EXEC_COMMAND_TYPE, ++ STATE_EXEC_COMMAND_INDEX, ++ STATE_EXEC_COMMAND_PATH, ++ STATE_EXEC_COMMAND_ARGS, ++ _STATE_EXEC_COMMAND_MAX, ++ _STATE_EXEC_COMMAND_INVALID = -1, ++ } state; ++ ++ assert(s); ++ assert(key); ++ assert(value); ++ ++ control = streq(key, "control-command"); ++ ++ state = STATE_EXEC_COMMAND_TYPE; ++ ++ for (;;) { ++ _cleanup_free_ char *arg = NULL; ++ ++ r = extract_first_word(&value, &arg, NULL, EXTRACT_CUNESCAPE); ++ if (r == 0) ++ break; ++ else if (r < 0) ++ return r; ++ ++ switch (state) { ++ case STATE_EXEC_COMMAND_TYPE: ++ id = service_exec_command_from_string(arg); ++ if (id < 0) ++ return -EINVAL; ++ ++ state = STATE_EXEC_COMMAND_INDEX; ++ break; ++ case STATE_EXEC_COMMAND_INDEX: ++ r = safe_atou(arg, &idx); ++ if (r < 0) ++ return -EINVAL; ++ ++ state = STATE_EXEC_COMMAND_PATH; ++ break; ++ case STATE_EXEC_COMMAND_PATH: ++ path = arg; ++ arg = NULL; ++ state = STATE_EXEC_COMMAND_ARGS; ++ ++ if (!path_is_absolute(path)) ++ return -EINVAL; ++ break; ++ case STATE_EXEC_COMMAND_ARGS: ++ r = strv_extend(&argv, arg); ++ if (r < 0) ++ return -ENOMEM; ++ break; ++ default: ++ assert_not_reached("Unknown error at deserialization of exec command"); ++ break; ++ } ++ } ++ ++ if (state != STATE_EXEC_COMMAND_ARGS) ++ return -EINVAL; ++ ++ /* Let's check whether exec command on given offset matches data that we just deserialized */ ++ for (command = s->exec_command[id], i = 0; command; command = command->command_next, i++) { ++ if (i != idx) ++ continue; ++ ++ found = strv_equal(argv, command->argv) && streq(command->path, path); ++ break; ++ } ++ ++ if (!found) { ++ /* Command at the index we serialized is different, let's look for command that exactly ++ * matches but is on different index. If there is no such command we will not resume execution. */ ++ for (command = s->exec_command[id]; command; command = command->command_next) ++ if (strv_equal(command->argv, argv) && streq(command->path, path)) ++ break; ++ } ++ ++ if (command && control) ++ s->control_command = command; ++ else if (command) ++ s->main_command = command; ++ else ++ log_unit_warning(u->id, "Current command vanished from the unit file, execution of the command list won't be resumed."); ++ ++ return 0; ++} ++ + static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + Service *s = SERVICE(u); + int r; +@@ -2105,16 +2275,11 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, + s->status_text = t; + } + +- } else if (streq(key, "control-command")) { +- ServiceExecCommand id; ++ } else if (STR_IN_SET(key, "main-command", "control-command")) { ++ r = service_deserialize_exec_command(u, key, value); ++ if (r < 0) ++ log_unit_debug_errno(u->id, r, "Failed to parse serialized command \"%s\": %m", value); + +- id = service_exec_command_from_string(value); +- if (id < 0) +- log_unit_debug(u->id, "Failed to parse exec-command value %s", value); +- else { +- s->control_command_id = id; +- s->control_command = s->exec_command[id]; +- } + } else if (streq(key, "socket-fd")) { + int fd; + diff --git a/SOURCES/0571-tests-add-new-test-for-issue-518.patch b/SOURCES/0571-tests-add-new-test-for-issue-518.patch new file mode 100644 index 0000000..252fc6b --- /dev/null +++ b/SOURCES/0571-tests-add-new-test-for-issue-518.patch @@ -0,0 +1,226 @@ +From 675af6905b424f2a927e4737a53f9b844e0cd9cc Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 15 Feb 2017 12:40:52 +0100 +Subject: [PATCH] tests: add new test for issue #518 + +(cherry picked from commit 123d672e85d0c52ff7cf81997d4910990da409c1) + +Related: #1404657, #1471230 +--- + Makefile.am | 3 +- + test/test-exec-deserialization.py | 192 ++++++++++++++++++++++++++++++++++++++ + 2 files changed, 194 insertions(+), 1 deletion(-) + create mode 100755 test/test-exec-deserialization.py + +diff --git a/Makefile.am b/Makefile.am +index f06bc29c2..c4a96e1fd 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -5711,7 +5711,8 @@ EXTRA_DIST += \ + src/network/networkd-network-gperf.gperf \ + src/network/networkd-netdev-gperf.gperf \ + units/systemd-networkd.service.in \ +- units/systemd-networkd-wait-online.service.in ++ units/systemd-networkd-wait-online.service.in \ ++ test/test-exec-deserialization.py + + CLEANFILES += \ + src/network/networkd-network-gperf.c \ +diff --git a/test/test-exec-deserialization.py b/test/test-exec-deserialization.py +new file mode 100755 +index 000000000..b974b1c13 +--- /dev/null ++++ b/test/test-exec-deserialization.py +@@ -0,0 +1,192 @@ ++#!/usr/bin/python3 ++ ++# ++# Copyright 2017 Michal Sekletar ++# ++# 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 . ++ ++# ATTENTION: This uses the *installed* systemd, not the one from the built ++# source tree. ++ ++import unittest ++import time ++import os ++import tempfile ++import subprocess ++ ++from enum import Enum ++ ++class UnitFileChange(Enum): ++ NO_CHANGE = 0 ++ LINES_SWAPPED = 1 ++ COMMAND_ADDED_BEFORE = 2 ++ COMMAND_ADDED_AFTER = 3 ++ COMMAND_INTERLEAVED = 4 ++ REMOVAL = 5 ++ ++class ExecutionResumeTest(unittest.TestCase): ++ def setUp(self): ++ self.unit = 'test-issue-518.service' ++ self.unitfile_path = '/run/systemd/system/{0}'.format(self.unit) ++ self.output_file = tempfile.mktemp() ++ self.unit_files = {} ++ ++ unit_file_content = ''' ++ [Service] ++ Type=oneshot ++ ExecStart=/bin/sleep 2 ++ ExecStart=/bin/bash -c "echo foo >> {0}" ++ '''.format(self.output_file) ++ self.unit_files[UnitFileChange.NO_CHANGE] = unit_file_content ++ ++ unit_file_content = ''' ++ [Service] ++ Type=oneshot ++ ExecStart=/bin/bash -c "echo foo >> {0}" ++ ExecStart=/bin/sleep 2 ++ '''.format(self.output_file) ++ self.unit_files[UnitFileChange.LINES_SWAPPED] = unit_file_content ++ ++ unit_file_content = ''' ++ [Service] ++ Type=oneshot ++ ExecStart=/bin/bash -c "echo bar >> {0}" ++ ExecStart=/bin/sleep 2 ++ ExecStart=/bin/bash -c "echo foo >> {0}" ++ '''.format(self.output_file) ++ self.unit_files[UnitFileChange.COMMAND_ADDED_BEFORE] = unit_file_content ++ ++ unit_file_content = ''' ++ [Service] ++ Type=oneshot ++ ExecStart=/bin/sleep 2 ++ ExecStart=/bin/bash -c "echo foo >> {0}" ++ ExecStart=/bin/bash -c "echo bar >> {0}" ++ '''.format(self.output_file) ++ self.unit_files[UnitFileChange.COMMAND_ADDED_AFTER] = unit_file_content ++ ++ unit_file_content = ''' ++ [Service] ++ Type=oneshot ++ ExecStart=/bin/bash -c "echo baz >> {0}" ++ ExecStart=/bin/sleep 2 ++ ExecStart=/bin/bash -c "echo foo >> {0}" ++ ExecStart=/bin/bash -c "echo bar >> {0}" ++ '''.format(self.output_file) ++ self.unit_files[UnitFileChange.COMMAND_INTERLEAVED] = unit_file_content ++ ++ unit_file_content = ''' ++ [Service] ++ Type=oneshot ++ ExecStart=/bin/bash -c "echo bar >> {0}" ++ ExecStart=/bin/bash -c "echo baz >> {0}" ++ '''.format(self.output_file) ++ self.unit_files[UnitFileChange.REMOVAL] = unit_file_content ++ ++ def reload(self): ++ subprocess.check_call(['systemctl', 'daemon-reload']) ++ ++ def write_unit_file(self, unit_file_change): ++ if not isinstance(unit_file_change, UnitFileChange): ++ raise ValueError('Unknown unit file change') ++ ++ content = self.unit_files[unit_file_change] ++ ++ with open(self.unitfile_path, 'w') as f: ++ f.write(content) ++ ++ self.reload() ++ ++ def check_output(self, expected_output): ++ try: ++ with open(self.output_file, 'r') as log: ++ output = log.read() ++ except IOError: ++ self.fail() ++ ++ self.assertEqual(output, expected_output) ++ ++ def setup_unit(self): ++ self.write_unit_file(UnitFileChange.NO_CHANGE) ++ subprocess.check_call(['systemctl', '--job-mode=replace', '--no-block', 'start', self.unit]) ++ ++ def test_no_change(self): ++ expected_output = 'foo\n' ++ ++ self.setup_unit() ++ self.reload() ++ time.sleep(4) ++ ++ self.check_output(expected_output) ++ ++ def test_swapped(self): ++ expected_output = '' ++ ++ self.setup_unit() ++ self.write_unit_file(UnitFileChange.LINES_SWAPPED) ++ self.reload() ++ time.sleep(4) ++ ++ self.assertTrue(not os.path.exists(self.output_file)) ++ ++ def test_added_before(self): ++ expected_output = 'foo\n' ++ ++ self.setup_unit() ++ self.write_unit_file(UnitFileChange.COMMAND_ADDED_BEFORE) ++ self.reload() ++ time.sleep(4) ++ ++ self.check_output(expected_output) ++ ++ def test_added_after(self): ++ expected_output = 'foo\nbar\n' ++ ++ self.setup_unit() ++ self.write_unit_file(UnitFileChange.COMMAND_ADDED_AFTER) ++ self.reload() ++ time.sleep(4) ++ ++ self.check_output(expected_output) ++ ++ def test_interleaved(self): ++ expected_output = 'foo\nbar\n' ++ ++ self.setup_unit() ++ self.write_unit_file(UnitFileChange.COMMAND_INTERLEAVED) ++ self.reload() ++ time.sleep(4) ++ ++ self.check_output(expected_output) ++ ++ def test_removal(self): ++ self.setup_unit() ++ self.write_unit_file(UnitFileChange.REMOVAL) ++ self.reload() ++ time.sleep(4) ++ ++ self.assertTrue(not os.path.exists(self.output_file)) ++ ++ def tearDown(self): ++ for f in [self.output_file, self.unitfile_path]: ++ try: ++ os.remove(f) ++ except OSError: ++ # ignore error if log file doesn't exist ++ pass ++ ++ self.reload() ++ ++if __name__ == '__main__': ++ unittest.main() diff --git a/SOURCES/0572-tests-in-RHEL-7-we-don-t-have-python3-by-default.patch b/SOURCES/0572-tests-in-RHEL-7-we-don-t-have-python3-by-default.patch new file mode 100644 index 0000000..cfd15f3 --- /dev/null +++ b/SOURCES/0572-tests-in-RHEL-7-we-don-t-have-python3-by-default.patch @@ -0,0 +1,27 @@ +From 8a8fa94333650d3c34fcd42b696598cdc930a876 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 2 Oct 2017 16:20:11 +0200 +Subject: [PATCH] tests: in RHEL-7 we don't have python3 by default + +Note that for running this test it is necessary to install backport of +enum package from python-3.4 to python2. + +yum install -y python-enum34 + +RHEL-only + +Related: #1404657, #1471230 +--- + test/test-exec-deserialization.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/test-exec-deserialization.py b/test/test-exec-deserialization.py +index b974b1c13..859778a7a 100755 +--- a/test/test-exec-deserialization.py ++++ b/test/test-exec-deserialization.py +@@ -1,4 +1,4 @@ +-#!/usr/bin/python3 ++#!/usr/bin/python + + # + # Copyright 2017 Michal Sekletar diff --git a/SOURCES/0573-service-attempt-to-execute-next-main-command-only-fo.patch b/SOURCES/0573-service-attempt-to-execute-next-main-command-only-fo.patch new file mode 100644 index 0000000..c922fe2 --- /dev/null +++ b/SOURCES/0573-service-attempt-to-execute-next-main-command-only-fo.patch @@ -0,0 +1,81 @@ +From 3bcdd03212c6f0a849a4fbdf3cc7cb99fb7327cb Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 25 Aug 2017 15:36:10 +0200 +Subject: [PATCH] service: attempt to execute next main command only for + oneshot services (#6619) + +This commit fixes crash described in +https://github.com/systemd/systemd/issues/6533 + +Multiple ExecStart lines are allowed only for oneshot services +anyway so it doesn't make sense to call service_run_next_main() with +services of type other than SERVICE_ONESHOT. + +Referring back to reproducer from the issue, previously we didn't observe +this problem because s->main_command was reset after daemon-reload hence +we never reached the assert statement in service_run_next_main(). + +Fixes #6533 + +(cherry picked from commit b58aeb70dbd1cab5908b003ef5187da1fc241839) + +Related: #1404657, #1471230 +--- + src/core/service.c | 1 + + test/test-exec-deserialization.py | 31 +++++++++++++++++++++++++++++++ + 2 files changed, 32 insertions(+) + +diff --git a/src/core/service.c b/src/core/service.c +index 9ad3a0eb0..ceed1cc2e 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -2612,6 +2612,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { + + if (s->main_command && + s->main_command->command_next && ++ s->type == SERVICE_ONESHOT && + f == SERVICE_SUCCESS) { + + /* There is another command to * +diff --git a/test/test-exec-deserialization.py b/test/test-exec-deserialization.py +index 859778a7a..61623da99 100755 +--- a/test/test-exec-deserialization.py ++++ b/test/test-exec-deserialization.py +@@ -178,6 +178,37 @@ class ExecutionResumeTest(unittest.TestCase): + + self.assertTrue(not os.path.exists(self.output_file)) + ++ def test_issue_6533(self): ++ unit = "test-issue-6533.service" ++ unitfile_path = "/run/systemd/system/{}".format(unit) ++ ++ content = ''' ++ [Service] ++ ExecStart=/bin/sleep 5 ++ ''' ++ ++ with open(unitfile_path, 'w') as f: ++ f.write(content) ++ ++ self.reload() ++ ++ subprocess.check_call(['systemctl', '--job-mode=replace', '--no-block', 'start', unit]) ++ time.sleep(2) ++ ++ content = ''' ++ [Service] ++ ExecStart=/bin/sleep 5 ++ ExecStart=/bin/true ++ ''' ++ ++ with open(unitfile_path, 'w') as f: ++ f.write(content) ++ ++ self.reload() ++ time.sleep(5) ++ ++ self.assertTrue(subprocess.call("journalctl -b _PID=1 | grep -q 'Freezing execution'", shell=True) != 0) ++ + def tearDown(self): + for f in [self.output_file, self.unitfile_path]: + try: diff --git a/SOURCES/0574-timedatectl-stop-using-xstrftime.patch b/SOURCES/0574-timedatectl-stop-using-xstrftime.patch new file mode 100644 index 0000000..762bbc8 --- /dev/null +++ b/SOURCES/0574-timedatectl-stop-using-xstrftime.patch @@ -0,0 +1,155 @@ +From add02d6e5934100f023b45584d0227be90a297e8 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 19 Oct 2017 09:53:56 +0200 +Subject: [PATCH] timedatectl: stop using xstrftime +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When using strftime in arbitrary locales, we cannot really say how big the +buffer should be. Let's make the buffer "large", which will work fine pretty +much always, and just print n/a if the timestamp does not fit. strftime returns +0 if the buffer is too small and a NUL-terminated string otherwise, so we +can drop the size specifications in string formatting. + +$ export LANG=fa_IR.UTF-8 +$ date +چهارشنبه ۱۸ اكتبر ۱۷، ساعت ۱۰:۵۴:۲۴ (+0330) +$ timedatectl +Assertion 'xstrftime: a[] must be big enough' failed at ../src/timedate/timedatectl.c:105, function print_status_info(). Aborting. + +now: + +$ timedatectl + Local time: چهارشنبه 2017-10-18 16:29:40 CEST + Universal time: چهارشنبه 2017-10-18 14:29:40 UTC + RTC time: چهارشنبه 2017-10-18 14:29:40 +… + +(cherry picked from commit 14ce0c25c28ba58e80084e28b4f23884199900e4) +Resolves: #1503942 +--- + src/shared/time-util.h | 2 -- + src/timedate/timedatectl.c | 49 ++++++++++++++++++++++++---------------------- + 2 files changed, 26 insertions(+), 25 deletions(-) + +diff --git a/src/shared/time-util.h b/src/shared/time-util.h +index f2789142f..32e90902a 100644 +--- a/src/shared/time-util.h ++++ b/src/shared/time-util.h +@@ -108,5 +108,3 @@ int get_timezones(char ***l); + bool timezone_is_valid(const char *name); + + clockid_t clock_boottime_or_monotonic(void); +- +-#define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0) +diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c +index 1accccb68..3e9b657bc 100644 +--- a/src/timedate/timedatectl.c ++++ b/src/timedate/timedatectl.c +@@ -93,8 +93,8 @@ static const char *jump_str(int delta_minutes, char *s, size_t size) { + } + + static void print_status_info(const StatusInfo *i) { +- char a[FORMAT_TIMESTAMP_MAX]; +- char b[FORMAT_TIMESTAMP_MAX]; ++ char a[LINE_MAX]; ++ char b[LINE_MAX]; + char s[32]; + struct tm tm; + time_t sec; +@@ -104,6 +104,7 @@ static void print_status_info(const StatusInfo *i) { + int dn = 0; + bool is_dstc = false, is_dstn = false; + int r; ++ size_t n; + + assert(i); + +@@ -123,11 +124,11 @@ static void print_status_info(const StatusInfo *i) { + fprintf(stderr, "Warning: Could not get time from timedated and not operating locally.\n\n"); + + if (have_time) { +- xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)); +- printf(" Local time: %.*s\n", (int) sizeof(a), a); ++ n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)); ++ printf(" Local time: %s\n", n > 0 ? a : "n/a"); + +- xstrftime(a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)); +- printf(" Universal time: %.*s\n", (int) sizeof(a), a); ++ n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)); ++ printf(" Universal time: %s\n", n > 0 ? a : "n/a"); + } else { + printf(" Local time: %s\n", "n/a"); + printf(" Universal time: %s\n", "n/a"); +@@ -137,24 +138,26 @@ static void print_status_info(const StatusInfo *i) { + time_t rtc_sec; + + rtc_sec = (time_t)(i->rtc_time / USEC_PER_SEC); +- xstrftime(a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm)); +- printf(" RTC time: %.*s\n", (int) sizeof(a), a); ++ n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm)); ++ printf(" RTC time: %s\n", n > 0 ? a : "n/a"); + } else + printf(" RTC time: %s\n", "n/a"); + + if (have_time) +- xstrftime(a, "%Z, %z", localtime_r(&sec, &tm)); ++ n = strftime(a, sizeof a, "%Z, %z", localtime_r(&sec, &tm)); + +- printf(" Time zone: %s (%.*s)\n" ++ printf(" Time zone: %s (%s)\n" + " NTP enabled: %s\n" + "NTP synchronized: %s\n" + " RTC in local TZ: %s\n", +- strna(i->timezone), (int) sizeof(a), have_time ? a : "n/a", ++ strna(i->timezone), have_time && n > 0 ? a : "n/a", + i->ntp_capable ? yes_no(i->ntp_enabled) : "n/a", + yes_no(i->ntp_synced), + yes_no(i->rtc_local)); + + if (have_time) { ++ size_t m; ++ + r = time_get_dst(sec, "/etc/localtime", + &tc, &zc, &is_dstc, + &tn, &dn, &zn, &is_dstn); +@@ -164,26 +167,26 @@ static void print_status_info(const StatusInfo *i) { + printf(" DST active: %s\n", yes_no(is_dstc)); + + t = tc - 1; +- xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)); ++ n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)); + +- xstrftime(b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)); ++ m = strftime(b, sizeof b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)); + printf(" Last DST change: DST %s at\n" +- " %.*s\n" +- " %.*s\n", ++ " %s\n" ++ " %s\n", + is_dstc ? "began" : "ended", +- (int) sizeof(a), a, +- (int) sizeof(b), b); ++ n > 0 ? a : "n/a", ++ m > 0 ? b : "n/a"); + + t = tn - 1; +- xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)); +- xstrftime(b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)); ++ n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)); ++ m = strftime(b, sizeof b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)); + printf(" Next DST change: DST %s (the clock jumps %s) at\n" +- " %.*s\n" +- " %.*s\n", ++ " %s\n" ++ " %s\n", + is_dstn ? "begins" : "ends", + jump_str(dn, s, sizeof(s)), +- (int) sizeof(a), a, +- (int) sizeof(b), b); ++ n > 0 ? a : "n/a", ++ m > 0 ? b : "n/a"); + } + } else + printf(" DST active: %s\n", yes_no(is_dstc)); diff --git a/SOURCES/0575-Add-support-to-read-lz4-compressed-journals.patch b/SOURCES/0575-Add-support-to-read-lz4-compressed-journals.patch new file mode 100644 index 0000000..8f6516a --- /dev/null +++ b/SOURCES/0575-Add-support-to-read-lz4-compressed-journals.patch @@ -0,0 +1,120 @@ +From bae0c1d66cba62b19d39a3a79cb76fbd5d4ef7e7 Mon Sep 17 00:00:00 2001 +From: Jan Rybar +Date: Thu, 17 Aug 2017 14:38:11 +0200 +Subject: [PATCH] Add support to read lz4 compressed journals + +Functionality already in codebase, but deactivated in RHEL +Changed calling of LZ4 functions due to deprecation of the originals. +Fixed typecasting of max_bytes to size_t in debuglog() + +Resolves: rhbz#1431687 + +changes to .spec file: + +@@ -552,6 +553,7 @@ BuildRequires: libblkid-devel + BuildRequires: xz-devel + BuildRequires: zlib-devel + BuildRequires: bzip2-devel ++BuildRequires: lz4-devel + BuildRequires: libidn-devel + BuildRequires: libcurl-devel + BuildRequires: kmod-devel +@@ -742,6 +744,7 @@ CONFIGURE_OPTS=( + --enable-compat-libs + --disable-sysusers + --disable-ldconfig ++ --enable-lz4 + %ifarch s390 s390x ppc %{power64} aarch64 + --disable-lto + %endif +--- + src/journal/compress.c | 11 ++++++++--- + src/journal/compress.h | 11 ----------- + src/journal/journal-file.c | 5 ++--- + 3 files changed, 10 insertions(+), 17 deletions(-) + +diff --git a/src/journal/compress.c b/src/journal/compress.c +index 4fb09f596..3baf9e4ad 100644 +--- a/src/journal/compress.c ++++ b/src/journal/compress.c +@@ -98,7 +98,12 @@ int compress_blob_lz4(const void *src, uint64_t src_size, void *dst, size_t *dst + if (src_size < 9) + return -ENOBUFS; + +- r = LZ4_compress_limitedOutput(src, dst + 8, src_size, src_size - 8 - 1); ++#if LZ4_VERSION_NUMBER >= 10700 ++ r = LZ4_compress_default(src, (char*)dst + 8, src_size, src_size - 8 - 1); ++#else ++ r = LZ4_compress_limitedOutput(src, (char*)dst + 8, src_size, src_size - 8 - 1); ++#endif ++ + if (r <= 0) + return -ENOBUFS; + +@@ -458,7 +463,7 @@ int compress_stream_lz4(int fdf, int fdt, off_t max_bytes) { + + total_in += n; + +- r = LZ4_compress_continue(&lz4_data, buf, out, n); ++ r = LZ4_compress_fast_continue(&lz4_data, buf, out, n, LZ4_COMPRESSBOUND(LZ4_BUFSIZE), 0); + if (r == 0) { + log_error("LZ4 compression failed."); + return -EBADMSG; +@@ -634,7 +639,7 @@ int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) { + total_out += r; + + if (max_bytes != -1 && total_out > (size_t) max_bytes) { +- log_debug("Decompressed stream longer than %zd bytes", max_bytes); ++ log_debug("Decompressed stream longer than %zd bytes", (size_t) max_bytes); + return -EFBIG; + } + +diff --git a/src/journal/compress.h b/src/journal/compress.h +index 136dda6d3..0f62a58d6 100644 +--- a/src/journal/compress.h ++++ b/src/journal/compress.h +@@ -35,15 +35,9 @@ int compress_blob_lz4(const void *src, uint64_t src_size, void *dst, size_t *dst + + static inline int compress_blob(const void *src, uint64_t src_size, void *dst, size_t *dst_size) { + int r; +-#ifdef HAVE_LZ4 +- r = compress_blob_lz4(src, src_size, dst, dst_size); +- if (r == 0) +- return OBJECT_COMPRESSED_LZ4; +-#else + r = compress_blob_xz(src, src_size, dst, dst_size); + if (r == 0) + return OBJECT_COMPRESSED_XZ; +-#endif + return r; + } + +@@ -75,12 +69,7 @@ int compress_stream_lz4(int fdf, int fdt, off_t max_bytes); + int decompress_stream_xz(int fdf, int fdt, off_t max_size); + int decompress_stream_lz4(int fdf, int fdt, off_t max_size); + +-#ifdef HAVE_LZ4 +-# define compress_stream compress_stream_lz4 +-# define COMPRESSED_EXT ".lz4" +-#else + # define compress_stream compress_stream_xz + # define COMPRESSED_EXT ".xz" +-#endif + + int decompress_stream(const char *filename, int fdf, int fdt, off_t max_bytes); +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 0fd59ec07..ebc8e6230 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -2615,9 +2615,8 @@ int journal_file_open( + f->flags = flags; + f->prot = prot_from_flags(flags); + f->writable = (flags & O_ACCMODE) != O_RDONLY; +-#if defined(HAVE_LZ4) +- f->compress_lz4 = compress; +-#elif defined(HAVE_XZ) ++ ++#if defined(HAVE_XZ) + f->compress_xz = compress; + #endif + #ifdef HAVE_GCRYPT diff --git a/SOURCES/0576-journald-never-block-when-sending-messages-on-NOTIFY.patch b/SOURCES/0576-journald-never-block-when-sending-messages-on-NOTIFY.patch new file mode 100644 index 0000000..8c40d40 --- /dev/null +++ b/SOURCES/0576-journald-never-block-when-sending-messages-on-NOTIFY.patch @@ -0,0 +1,449 @@ +From c67c643418b1df5b5705b3a72eba1e6755830dc5 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 21 Nov 2017 12:46:28 +0100 +Subject: [PATCH] journald: never block when sending messages on NOTIFY_SOCKET + socket + +Otherwise we might run into deadlocks, when journald blocks on the +notify socket on PID 1, and PID 1 blocks on IPC to dbus-daemon and +dbus-daemon blocks on logging to journald. Break this cycle by making +sure that journald never ever blocks on PID 1. + +Note that this change disables support for event loop watchdog support, +as these messages are sent in blocking style by sd-event. That should +not be a big loss though, as people reported frequent problems with the +watchdog hitting journald on excessively slow IO. + +Fixes: #1505. +(cherry-picked from commit e22aa3d3284709234f086ebebc13a905a295b7a7) + +Resolves: #1511565 +--- + src/journal/journald-server.c | 130 +++++++++++++++++++++++++++++++++++++- + src/journal/journald-server.h | 13 ++-- + src/journal/journald-stream.c | 68 ++++++++++++++++++-- + src/journal/journald-stream.h | 3 + + src/journal/journald.c | 8 --- + units/systemd-journald.service.in | 1 - + 6 files changed, 201 insertions(+), 22 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index daeecd519..a810829b2 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -67,6 +67,8 @@ + + #define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC) + ++#define NOTIFY_SNDBUF_SIZE (8*1024*1024) ++ + /* Pick a good default that is likely to fit into AF_UNIX and AF_INET SOCK_DGRAM datagrams, and even leaves some room + + * for a bit of additional metadata. */ + #define DEFAULT_LINE_MAX (48*1024) +@@ -1556,6 +1558,126 @@ static int server_open_hostname(Server *s) { + return 0; + } + ++static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata) { ++ Server *s = userdata; ++ int r; ++ ++ assert(s); ++ assert(s->notify_event_source == es); ++ assert(s->notify_fd == fd); ++ ++ if (revents != EPOLLOUT) { ++ log_error("Invalid events on notify file descriptor."); ++ return -EINVAL; ++ } ++ ++ /* The $NOTIFY_SOCKET is writable again, now send exactly one ++ * message on it. Either it's the initial READY=1 event or an ++ * stdout stream event. If there's nothing to write anymore, ++ * turn our event source off. The next time there's something ++ * to send it will be turned on again. */ ++ ++ if (!s->sent_notify_ready) { ++ static const char p[] = ++ "READY=1\n" ++ "STATUS=Processing requests..."; ++ ssize_t l; ++ ++ l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT); ++ if (l < 0) { ++ if (errno == EAGAIN) ++ return 0; ++ ++ return log_error_errno(errno, "Failed to send READY=1 notification message: %m"); ++ } ++ ++ s->sent_notify_ready = true; ++ log_debug("Sent READY=1 notification."); ++ ++ } else if (s->stdout_streams_notify_queue) ++ /* Dispatch one stream notification event */ ++ stdout_stream_send_notify(s->stdout_streams_notify_queue); ++ ++ /* Leave us enabled if there's still more to to do. */ ++ if (s->stdout_streams_notify_queue) ++ return 0; ++ ++ /* There was nothing to do anymore, let's turn ourselves off. */ ++ r = sd_event_source_set_enabled(es, SD_EVENT_OFF); ++ if (r < 0) ++ return log_error_errno(r, "Failed to turn off notify event source: %m"); ++ ++ return 0; ++} ++ ++static int server_connect_notify(Server *s) { ++ union sockaddr_union sa = { ++ .un.sun_family = AF_UNIX, ++ }; ++ const char *e; ++ int r; ++ ++ assert(s); ++ assert(s->notify_fd < 0); ++ assert(!s->notify_event_source); ++ ++ /* ++ So here's the problem: we'd like to send notification ++ messages to PID 1, but we cannot do that via sd_notify(), ++ since that's synchronous, and we might end up blocking on ++ it. Specifically: given that PID 1 might block on ++ dbus-daemon during IPC, and dbus-daemon is logging to us, ++ and might hence block on us, we might end up in a deadlock ++ if we block on sending PID 1 notification messages -- by ++ generating a full blocking circle. To avoid this, let's ++ create a non-blocking socket, and connect it to the ++ notification socket, and then wait for POLLOUT before we ++ send anything. This should efficiently avoid any deadlocks, ++ as we'll never block on PID 1, hence PID 1 can safely block ++ on dbus-daemon which can safely block on us again. ++ ++ Don't think that this issue is real? It is, see: ++ https://github.com/systemd/systemd/issues/1505 ++ */ ++ ++ e = getenv("NOTIFY_SOCKET"); ++ if (!e) ++ return 0; ++ ++ if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { ++ log_error("NOTIFY_SOCKET set to an invalid value: %s", e); ++ return -EINVAL; ++ } ++ ++ if (strlen(e) > sizeof(sa.un.sun_path)) { ++ log_error("NOTIFY_SOCKET path too long: %s", e); ++ return -EINVAL; ++ } ++ ++ s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); ++ if (s->notify_fd < 0) ++ return log_error_errno(errno, "Failed to create notify socket: %m"); ++ ++ (void) fd_inc_sndbuf(s->notify_fd, NOTIFY_SNDBUF_SIZE); ++ ++ strncpy(sa.un.sun_path, e, sizeof(sa.un.sun_path)); ++ if (sa.un.sun_path[0] == '@') ++ sa.un.sun_path[0] = 0; ++ ++ r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e)); ++ if (r < 0) ++ return log_error_errno(errno, "Failed to connect to notify socket: %m"); ++ ++ r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s); ++ if (r < 0) ++ return log_error_errno(r, "Failed to watch notification socket: %m"); ++ ++ /* This should fire pretty soon, which we'll use to send the ++ * READY=1 event. */ ++ ++ return 0; ++} ++ + int server_init(Server *s) { + _cleanup_fdset_free_ FDSet *fds = NULL; + int n, r, fd; +@@ -1563,7 +1685,7 @@ int server_init(Server *s) { + assert(s); + + zero(*s); +- s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1; ++ s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1; + s->compress = true; + s->seal = true; + +@@ -1611,8 +1733,6 @@ int server_init(Server *s) { + if (r < 0) + return log_error_errno(r, "Failed to create event loop: %m"); + +- sd_event_set_watchdog(s->event, true); +- + n = sd_listen_fds(true); + if (n < 0) + return log_error_errno(n, "Failed to read listening file descriptors from environment: %m"); +@@ -1718,6 +1838,8 @@ int server_init(Server *s) { + server_cache_boot_id(s); + server_cache_machine_id(s); + ++ (void) server_connect_notify(s); ++ + r = system_journal_open(s, false); + if (r < 0) + return r; +@@ -1770,6 +1892,7 @@ void server_done(Server *s) { + sd_event_source_unref(s->sigterm_event_source); + sd_event_source_unref(s->sigint_event_source); + sd_event_source_unref(s->hostname_event_source); ++ sd_event_source_unref(s->notify_event_source); + sd_event_unref(s->event); + + safe_close(s->syslog_fd); +@@ -1778,6 +1901,7 @@ void server_done(Server *s) { + safe_close(s->dev_kmsg_fd); + safe_close(s->audit_fd); + safe_close(s->hostname_fd); ++ safe_close(s->notify_fd); + + if (s->rate_limit) + journal_rate_limit_free(s->rate_limit); +diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h +index b29410778..e59ff35e2 100644 +--- a/src/journal/journald-server.h ++++ b/src/journal/journald-server.h +@@ -27,12 +27,15 @@ + #include + #include + ++typedef struct Server Server; ++ + #include "sd-event.h" + #include "journal-file.h" + #include "hashmap.h" + #include "util.h" + #include "audit.h" + #include "journald-rate-limit.h" ++#include "journald-stream.h" + #include "list.h" + + typedef enum Storage { +@@ -52,15 +55,14 @@ typedef enum SplitMode { + _SPLIT_INVALID = -1 + } SplitMode; + +-typedef struct StdoutStream StdoutStream; +- +-typedef struct Server { ++struct Server { + int syslog_fd; + int native_fd; + int stdout_fd; + int dev_kmsg_fd; + int audit_fd; + int hostname_fd; ++ int notify_fd; + + sd_event *event; + +@@ -75,6 +77,7 @@ typedef struct Server { + sd_event_source *sigterm_event_source; + sd_event_source *sigint_event_source; + sd_event_source *hostname_event_source; ++ sd_event_source *notify_event_source; + + JournalFile *runtime_journal; + JournalFile *system_journal; +@@ -114,6 +117,7 @@ typedef struct Server { + usec_t oldest_file_usec; + + LIST_HEAD(StdoutStream, stdout_streams); ++ LIST_HEAD(StdoutStream, stdout_streams_notify_queue); + unsigned n_stdout_streams; + + char *tty_path; +@@ -135,6 +139,7 @@ typedef struct Server { + + struct udev *udev; + ++ bool sent_notify_ready; + bool sync_scheduled; + + char machine_id_field[sizeof("_MACHINE_ID=") + 32]; +@@ -145,7 +150,7 @@ typedef struct Server { + char *cgroup_root; + + size_t line_max; +-} Server; ++}; + + #define N_IOVEC_META_FIELDS 20 + #define N_IOVEC_KERNEL_FIELDS 64 +diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c +index 4d6b7ad18..9118d1a31 100644 +--- a/src/journal/journald-stream.c ++++ b/src/journal/journald-stream.c +@@ -80,6 +80,7 @@ struct StdoutStream { + bool forward_to_console:1; + + bool fdstore:1; ++ bool in_notify_queue:1; + + char *buffer; + size_t length; +@@ -90,6 +91,7 @@ struct StdoutStream { + char *state_file; + + LIST_FIELDS(StdoutStream, stdout_stream); ++ LIST_FIELDS(StdoutStream, stdout_stream_notify_queue); + + char id_field[sizeof("_STREAM_ID=")-1 + SD_ID128_STRING_MAX]; + }; +@@ -102,6 +104,9 @@ void stdout_stream_free(StdoutStream *s) { + assert(s->server->n_stdout_streams > 0); + s->server->n_stdout_streams --; + LIST_REMOVE(stdout_stream, s->server->stdout_streams, s); ++ ++ if (s->in_notify_queue) ++ LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); + } + + if (s->event_source) { +@@ -126,7 +131,7 @@ static void stdout_stream_destroy(StdoutStream *s) { + return; + + if (s->state_file) +- unlink(s->state_file); ++ (void) unlink(s->state_file); + + stdout_stream_free(s); + } +@@ -210,11 +215,15 @@ static int stdout_stream_save(StdoutStream *s) { + free(temp_path); + temp_path = NULL; + +- /* Store the connection fd in PID 1, so that we get it passed +- * in again on next start */ +- if (!s->fdstore) { +- sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1); +- s->fdstore = true; ++ if (!s->fdstore && !s->in_notify_queue) { ++ LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); ++ s->in_notify_queue = true; ++ ++ if (s->server->notify_event_source) { ++ r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON); ++ if (r < 0) ++ log_warning_errno(r, "Failed to enable notify event source: %m"); ++ } + } + + finish: +@@ -801,3 +810,50 @@ int server_open_stdout_socket(Server *s, FDSet *fds) { + + return 0; + } ++ ++void stdout_stream_send_notify(StdoutStream *s) { ++ struct iovec iovec = { ++ .iov_base = (char*) "FDSTORE=1", ++ .iov_len = strlen("FDSTORE=1"), ++ }; ++ struct msghdr msghdr = { ++ .msg_iov = &iovec, ++ .msg_iovlen = 1, ++ }; ++ struct cmsghdr *cmsg; ++ ssize_t l; ++ ++ assert(s); ++ assert(!s->fdstore); ++ assert(s->in_notify_queue); ++ assert(s->server); ++ assert(s->server->notify_fd >= 0); ++ ++ /* Store the connection fd in PID 1, so that we get it passed ++ * in again on next start */ ++ ++ msghdr.msg_controllen = CMSG_SPACE(sizeof(int)); ++ msghdr.msg_control = alloca0(msghdr.msg_controllen); ++ ++ cmsg = CMSG_FIRSTHDR(&msghdr); ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_RIGHTS; ++ cmsg->cmsg_len = CMSG_LEN(sizeof(int)); ++ ++ memcpy(CMSG_DATA(cmsg), &s->fd, sizeof(int)); ++ ++ l = sendmsg(s->server->notify_fd, &msghdr, MSG_DONTWAIT|MSG_NOSIGNAL); ++ if (l < 0) { ++ if (errno == EAGAIN) ++ return; ++ ++ log_error_errno(errno, "Failed to send stream file descriptor to service manager: %m"); ++ } else { ++ log_debug("Successfully sent stream file descriptor to service manager."); ++ s->fdstore = 1; ++ } ++ ++ LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); ++ s->in_notify_queue = false; ++ ++} +diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h +index 94bf955d7..fd8c94fb6 100644 +--- a/src/journal/journald-stream.h ++++ b/src/journal/journald-stream.h +@@ -21,9 +21,12 @@ + along with systemd; If not, see . + ***/ + ++typedef struct StdoutStream StdoutStream; ++ + #include "fdset.h" + #include "journald-server.h" + + int server_open_stdout_socket(Server *s, FDSet *fds); + + void stdout_stream_free(StdoutStream *s); ++void stdout_stream_send_notify(StdoutStream *s); +diff --git a/src/journal/journald.c b/src/journal/journald.c +index 15bbcbe3d..b7ba2b6ec 100644 +--- a/src/journal/journald.c ++++ b/src/journal/journald.c +@@ -64,10 +64,6 @@ int main(int argc, char *argv[]) { + log_debug("systemd-journald running as pid "PID_FMT, getpid()); + server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started"); + +- sd_notify(false, +- "READY=1\n" +- "STATUS=Processing requests..."); +- + for (;;) { + usec_t t = USEC_INFINITY, n; + +@@ -120,10 +116,6 @@ int main(int argc, char *argv[]) { + server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped"); + + finish: +- sd_notify(false, +- "STOPPING=1\n" +- "STATUS=Shutting down..."); +- + server_done(&server); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index 0d1ea61fe..c94c0bfba 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -22,7 +22,6 @@ RestartSec=0 + StandardOutput=null + FileDescriptorStoreMax=4224 + 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=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/SOURCES/0577-journal-restore-watchdog-support.patch b/SOURCES/0577-journal-restore-watchdog-support.patch new file mode 100644 index 0000000..0fa5760 --- /dev/null +++ b/SOURCES/0577-journal-restore-watchdog-support.patch @@ -0,0 +1,184 @@ +From 652a44f9a9948a023fd7b26f72044fea0b13c25d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 3 Nov 2015 12:28:19 +0100 +Subject: [PATCH] journal: restore watchdog support + +(cherry picked from commit 119e9655dc36f18ed74f9a256d5c693b5aeb43ab) + +Conflicts: + src/journal/journald-server.h + units/systemd-journald.service.in + +Related: #1511565 +--- + src/journal/journald-server.c | 62 +++++++++++++++++++++++++++++++++++---- + src/journal/journald-server.h | 13 ++++---- + units/systemd-journald.service.in | 1 + + 3 files changed, 66 insertions(+), 10 deletions(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index a810829b2..6e7568b60 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1572,10 +1572,10 @@ static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, + } + + /* The $NOTIFY_SOCKET is writable again, now send exactly one +- * message on it. Either it's the initial READY=1 event or an +- * stdout stream event. If there's nothing to write anymore, +- * turn our event source off. The next time there's something +- * to send it will be turned on again. */ ++ * message on it. Either it's the wtachdog event, the initial ++ * READY=1 event or an stdout stream event. If there's nothing ++ * to write anymore, turn our event source off. The next time ++ * there's something to send it will be turned on again. */ + + if (!s->sent_notify_ready) { + static const char p[] = +@@ -1594,12 +1594,30 @@ static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, + s->sent_notify_ready = true; + log_debug("Sent READY=1 notification."); + ++ } else if (s->send_watchdog) { ++ ++ static const char p[] = ++ "WATCHDOG=1"; ++ ++ ssize_t l; ++ ++ l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT); ++ if (l < 0) { ++ if (errno == EAGAIN) ++ return 0; ++ ++ return log_error_errno(errno, "Failed to send WATCHDOG=1 notification message: %m"); ++ } ++ ++ s->send_watchdog = false; ++ log_debug("Sent WATCHDOG=1 notification."); ++ + } else if (s->stdout_streams_notify_queue) + /* Dispatch one stream notification event */ + stdout_stream_send_notify(s->stdout_streams_notify_queue); + + /* Leave us enabled if there's still more to to do. */ +- if (s->stdout_streams_notify_queue) ++ if (s->send_watchdog || s->stdout_streams_notify_queue) + return 0; + + /* There was nothing to do anymore, let's turn ourselves off. */ +@@ -1610,6 +1628,29 @@ static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, + return 0; + } + ++static int dispatch_watchdog(sd_event_source *es, uint64_t usec, void *userdata) { ++ Server *s = userdata; ++ int r; ++ ++ assert(s); ++ ++ s->send_watchdog = true; ++ ++ r = sd_event_source_set_enabled(s->notify_event_source, SD_EVENT_ON); ++ if (r < 0) ++ log_warning_errno(r, "Failed to turn on notify event source: %m"); ++ ++ r = sd_event_source_set_time(s->watchdog_event_source, usec + s->watchdog_usec / 2); ++ if (r < 0) ++ return log_error_errno(r, "Failed to restart watchdog event source: %m"); ++ ++ r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ON); ++ if (r < 0) ++ return log_error_errno(r, "Failed to enable watchdog event source: %m"); ++ ++ return 0; ++} ++ + static int server_connect_notify(Server *s) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, +@@ -1672,6 +1713,14 @@ static int server_connect_notify(Server *s) { + if (r < 0) + return log_error_errno(r, "Failed to watch notification socket: %m"); + ++ if (sd_watchdog_enabled(false, &s->watchdog_usec) > 0) { ++ s->send_watchdog = true; ++ ++ r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec*3/4, dispatch_watchdog, s); ++ if (r < 0) ++ return log_error_errno(r, "Failed to add watchdog time event: %m"); ++ } ++ + /* This should fire pretty soon, which we'll use to send the + * READY=1 event. */ + +@@ -1689,6 +1738,8 @@ int server_init(Server *s) { + s->compress = true; + s->seal = true; + ++ s->watchdog_usec = USEC_INFINITY; ++ + s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC; + s->sync_scheduled = false; + +@@ -1893,6 +1944,7 @@ void server_done(Server *s) { + sd_event_source_unref(s->sigint_event_source); + sd_event_source_unref(s->hostname_event_source); + sd_event_source_unref(s->notify_event_source); ++ sd_event_source_unref(s->watchdog_event_source); + sd_event_unref(s->event); + + safe_close(s->syslog_fd); +diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h +index e59ff35e2..f046fde83 100644 +--- a/src/journal/journald-server.h ++++ b/src/journal/journald-server.h +@@ -78,6 +78,7 @@ struct Server { + sd_event_source *sigint_event_source; + sd_event_source *hostname_event_source; + sd_event_source *notify_event_source; ++ sd_event_source *watchdog_event_source; + + JournalFile *runtime_journal; + JournalFile *system_journal; +@@ -133,14 +134,14 @@ struct Server { + + MMapCache *mmap; + +- bool dev_kmsg_readable; ++ struct udev *udev; + + uint64_t *kernel_seqnum; ++ bool dev_kmsg_readable:1; + +- struct udev *udev; +- +- bool sent_notify_ready; +- bool sync_scheduled; ++ bool send_watchdog:1; ++ bool sent_notify_ready:1; ++ bool sync_scheduled:1; + + char machine_id_field[sizeof("_MACHINE_ID=") + 32]; + char boot_id_field[sizeof("_BOOT_ID=") + 32]; +@@ -149,6 +150,8 @@ struct Server { + /* Cached cgroup root, so that we don't have to query that all the time */ + char *cgroup_root; + ++ usec_t watchdog_usec; ++ + size_t line_max; + }; + +diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in +index c94c0bfba..0d1ea61fe 100644 +--- a/units/systemd-journald.service.in ++++ b/units/systemd-journald.service.in +@@ -22,6 +22,7 @@ RestartSec=0 + StandardOutput=null + FileDescriptorStoreMax=4224 + 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=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/SOURCES/0578-cgroup-resource-property-setting-ignored-if-einval.patch b/SOURCES/0578-cgroup-resource-property-setting-ignored-if-einval.patch new file mode 100644 index 0000000..38d71eb --- /dev/null +++ b/SOURCES/0578-cgroup-resource-property-setting-ignored-if-einval.patch @@ -0,0 +1,729 @@ +From cbeadf0e57c0d240977d574a8b5726b441f519a9 Mon Sep 17 00:00:00 2001 +From: Jan Rybar +Date: Fri, 22 Sep 2017 11:53:50 +0200 +Subject: [PATCH] cgroup resource property setting ignored if einval + +Resolves: rhbz#1302305 +Cherry-picked from: d53d94743c5e5e3a4a6, 3fdf9ad +--- + man/systemd.resource-control.xml | 9 +-- + src/core/cgroup.c | 54 +++++++++-------- + src/core/cgroup.h | 14 ++--- + src/core/dbus-cgroup.c | 125 +++++++++++++++------------------------ + src/core/load-fragment.c | 54 +++++++---------- + src/core/unit.c | 4 +- + src/libsystemd/sd-bus/bus-util.c | 35 +++++++---- + src/shared/cgroup-util.c | 41 +++++++++++++ + src/shared/cgroup-util.h | 27 +++++++++ + 9 files changed, 205 insertions(+), 158 deletions(-) + +diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml +index f507c6748..6ab17e8cb 100644 +--- a/man/systemd.resource-control.xml ++++ b/man/systemd.resource-control.xml +@@ -118,10 +118,11 @@ + + + Assign the specified CPU time share weight to the +- processes executed. Those options take an integer value and ++ processes executed. These options take an integer value and + control the cpu.shares control group +- attribute, which defaults to 1024. For details about this +- control group attribute, see sched-design-CFS.txt. + The available CPU time is split up among all units within + one slice relative to their CPU time share weight. +@@ -258,7 +259,7 @@ + the executed processes. Takes a single weight value (between + 10 and 1000) to set the default block IO weight. This controls + the blkio.weight control group attribute, +- which defaults to 1000. For details about this control group ++ which defaults to 500. For details about this control group + attribute, see blkio-controller.txt. + The available IO bandwidth is split up among all units within +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index d4a8f9cbe..0779fa555 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -35,14 +35,16 @@ void cgroup_context_init(CGroupContext *c) { + /* Initialize everything to the kernel defaults, assuming the + * structure is preinitialized to 0 */ + +- c->cpu_shares = (unsigned long) -1; +- c->startup_cpu_shares = (unsigned long) -1; ++ c->cpu_shares = CGROUP_CPU_SHARES_INVALID; ++ c->startup_cpu_shares = CGROUP_CPU_SHARES_INVALID; ++ c->cpu_quota_per_sec_usec = USEC_INFINITY; ++ + c->memory_limit = (uint64_t) -1; +- c->blockio_weight = (unsigned long) -1; +- c->startup_blockio_weight = (unsigned long) -1; +- c->tasks_max = (uint64_t) -1; + +- c->cpu_quota_per_sec_usec = USEC_INFINITY; ++ c->blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID; ++ c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID; ++ ++ c->tasks_max = (uint64_t) -1; + } + + void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) { +@@ -100,11 +102,12 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { + "%sCPUAccounting=%s\n" + "%sBlockIOAccounting=%s\n" + "%sMemoryAccounting=%s\n" +- "%sCPUShares=%lu\n" +- "%sStartupCPUShares=%lu\n" ++ "%sTasksAccounting=%s\n" ++ "%sCPUShares=%" PRIu64 "\n" ++ "%sStartupCPUShares=%" PRIu64 "\n" + "%sCPUQuotaPerSecSec=%s\n" +- "%sBlockIOWeight=%lu\n" +- "%sStartupBlockIOWeight=%lu\n" ++ "%sBlockIOWeight=%" PRIu64 "\n" ++ "%sStartupBlockIOWeight=%" PRIu64 "\n" + "%sMemoryLimit=%" PRIu64 "\n" + "%sTasksMax=%" PRIu64 "\n" + "%sDevicePolicy=%s\n" +@@ -112,6 +115,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { + prefix, yes_no(c->cpu_accounting), + prefix, yes_no(c->blockio_accounting), + prefix, yes_no(c->memory_accounting), ++ prefix, yes_no(c->tasks_accounting), + prefix, c->cpu_shares, + prefix, c->startup_cpu_shares, + prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1), +@@ -131,7 +135,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { + + LIST_FOREACH(device_weights, w, c->blockio_device_weights) + fprintf(f, +- "%sBlockIODeviceWeight=%s %lu", ++ "%sBlockIODeviceWeight=%s %" PRIu64, + prefix, + w->path, + w->weight); +@@ -307,11 +311,11 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha + * and missing cgroups, i.e. EROFS and ENOENT. */ + + if ((mask & CGROUP_CPU) && !is_root) { +- char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1]; ++ char buf[MAX(DECIMAL_STR_MAX(uint64_t), DECIMAL_STR_MAX(usec_t)) + 1]; + +- sprintf(buf, "%lu\n", +- IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != (unsigned long) -1 ? c->startup_cpu_shares : +- c->cpu_shares != (unsigned long) -1 ? c->cpu_shares : 1024); ++ sprintf(buf, "%" PRIu64 "\n", ++ IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->startup_cpu_shares : ++ c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT); + r = cg_set_attribute("cpu", path, "cpu.shares", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, +@@ -334,15 +338,15 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha + } + + if (mask & CGROUP_BLKIO) { +- char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1, +- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1, +- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; ++ char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1, ++ DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)]; + CGroupBlockIODeviceWeight *w; + CGroupBlockIODeviceBandwidth *b; + + if (!is_root) { +- sprintf(buf, "%lu\n", IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != (unsigned long) -1 ? c->startup_blockio_weight : +- c->blockio_weight != (unsigned long) -1 ? c->blockio_weight : 1000); ++ sprintf(buf, "%" PRIu64 "\n", ++ IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->startup_blockio_weight : ++ c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT); + r = cg_set_attribute("blkio", path, "blkio.weight", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, +@@ -356,7 +360,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha + if (r < 0) + continue; + +- sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight); ++ sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight); + r = cg_set_attribute("blkio", path, "blkio.weight_device", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, +@@ -482,14 +486,14 @@ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) { + /* Figure out which controllers we need */ + + if (c->cpu_accounting || +- c->cpu_shares != (unsigned long) -1 || +- c->startup_cpu_shares != (unsigned long) -1 || ++ c->cpu_shares != CGROUP_CPU_SHARES_INVALID || ++ c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID || + c->cpu_quota_per_sec_usec != USEC_INFINITY) + mask |= CGROUP_CPUACCT | CGROUP_CPU; + + if (c->blockio_accounting || +- c->blockio_weight != (unsigned long) -1 || +- c->startup_blockio_weight != (unsigned long) -1 || ++ c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || ++ c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID || + c->blockio_device_weights || + c->blockio_device_bandwidths) + mask |= CGROUP_BLKIO; +diff --git a/src/core/cgroup.h b/src/core/cgroup.h +index 8af3eaa3a..870f39c52 100644 +--- a/src/core/cgroup.h ++++ b/src/core/cgroup.h +@@ -58,7 +58,7 @@ struct CGroupDeviceAllow { + struct CGroupBlockIODeviceWeight { + LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights); + char *path; +- unsigned long weight; ++ uint64_t weight; + }; + + struct CGroupBlockIODeviceBandwidth { +@@ -74,12 +74,12 @@ struct CGroupContext { + bool memory_accounting; + bool tasks_accounting; + +- unsigned long cpu_shares; +- unsigned long startup_cpu_shares; ++ uint64_t cpu_shares; ++ uint64_t startup_cpu_shares; + usec_t cpu_quota_per_sec_usec; + +- unsigned long blockio_weight; +- unsigned long startup_blockio_weight; ++ uint64_t blockio_weight; ++ uint64_t startup_blockio_weight; + LIST_HEAD(CGroupBlockIODeviceWeight, blockio_device_weights); + LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths); + +@@ -88,9 +88,9 @@ struct CGroupContext { + CGroupDevicePolicy device_policy; + LIST_HEAD(CGroupDeviceAllow, device_allow); + +- bool delegate; +- + uint64_t tasks_max; ++ ++ bool delegate; + }; + + #include "unit.h" +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index fa76c60c1..ffeeb5aa9 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -133,34 +133,16 @@ static int property_get_device_allow( + return sd_bus_message_close_container(reply); + } + +-static int property_get_ulong_as_u64( +- sd_bus *bus, +- const char *path, +- const char *interface, +- const char *property, +- sd_bus_message *reply, +- void *userdata, +- sd_bus_error *error) { +- +- unsigned long *ul = userdata; +- +- assert(bus); +- assert(reply); +- assert(ul); +- +- return sd_bus_message_append(reply, "t", *ul == (unsigned long) -1 ? (uint64_t) -1 : (uint64_t) *ul); +-} +- + const sd_bus_vtable bus_cgroup_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0), + SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0), +- SD_BUS_PROPERTY("CPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, cpu_shares), 0), +- SD_BUS_PROPERTY("StartupCPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_cpu_shares), 0), ++ SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0), ++ SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0), + SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0), + SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0), +- SD_BUS_PROPERTY("BlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, blockio_weight), 0), +- SD_BUS_PROPERTY("StartupBlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_blockio_weight), 0), ++ SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0), ++ SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0), + SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0), + SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), + SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), +@@ -237,49 +219,45 @@ int bus_cgroup_set_property( + return 1; + + } else if (streq(name, "CPUShares")) { +- uint64_t u64; +- unsigned long ul; ++ uint64_t shares; + +- r = sd_bus_message_read(message, "t", &u64); ++ r = sd_bus_message_read(message, "t", &shares); + if (r < 0) + return r; + +- if (u64 == (uint64_t) -1) +- ul = (unsigned long) -1; +- else { +- ul = (unsigned long) u64; +- if (ul <= 0 || (uint64_t) ul != u64) +- return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range"); +- } ++ if (!CGROUP_CPU_SHARES_IS_OK(shares)) ++ return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range"); + + if (mode != UNIT_CHECK) { +- c->cpu_shares = ul; ++ c->cpu_shares = shares; + u->cgroup_realized_mask &= ~CGROUP_CPU; +- unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul); ++ ++ if (shares == CGROUP_CPU_SHARES_INVALID) ++ unit_write_drop_in_private(u, mode, name, "CPUShares="); ++ else ++ unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares); + } + + return 1; + + } else if (streq(name, "StartupCPUShares")) { +- uint64_t u64; +- unsigned long ul; ++ uint64_t shares; + +- r = sd_bus_message_read(message, "t", &u64); ++ r = sd_bus_message_read(message, "t", &shares); + if (r < 0) + return r; + +- if (u64 == (uint64_t) -1) +- ul = (unsigned long) -1; +- else { +- ul = (unsigned long) u64; +- if (ul <= 0 || (uint64_t) ul != u64) +- return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range"); +- } ++ if (!CGROUP_CPU_SHARES_IS_OK(shares)) ++ return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range"); + + if (mode != UNIT_CHECK) { +- c->startup_cpu_shares = ul; ++ c->startup_cpu_shares = shares; + u->cgroup_realized_mask &= ~CGROUP_CPU; +- unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul); ++ ++ if (shares == CGROUP_CPU_SHARES_INVALID) ++ unit_write_drop_in_private(u, mode, name, "StartupCPUShares="); ++ else ++ unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares); + } + + return 1; +@@ -318,49 +296,45 @@ int bus_cgroup_set_property( + return 1; + + } else if (streq(name, "BlockIOWeight")) { +- uint64_t u64; +- unsigned long ul; ++ uint64_t weight; + +- r = sd_bus_message_read(message, "t", &u64); ++ r = sd_bus_message_read(message, "t", &weight); + if (r < 0) + return r; + +- if (u64 == (uint64_t) -1) +- ul = (unsigned long) -1; +- else { +- ul = (unsigned long) u64; +- if (ul < 10 || ul > 1000) +- return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range"); +- } ++ if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight)) ++ return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range"); + + if (mode != UNIT_CHECK) { +- c->blockio_weight = ul; ++ c->blockio_weight = weight; + u->cgroup_realized_mask &= ~CGROUP_BLKIO; +- unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul); ++ ++ if (weight == CGROUP_BLKIO_WEIGHT_INVALID) ++ unit_write_drop_in_private(u, mode, name, "BlockIOWeight="); ++ else ++ unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight); + } + + return 1; + + } else if (streq(name, "StartupBlockIOWeight")) { +- uint64_t u64; +- unsigned long ul; ++ uint64_t weight; + +- r = sd_bus_message_read(message, "t", &u64); ++ r = sd_bus_message_read(message, "t", &weight); + if (r < 0) + return r; + +- if (u64 == (uint64_t) -1) +- ul = (unsigned long) -1; +- else { +- ul = (unsigned long) u64; +- if (ul < 10 || ul > 1000) +- return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range"); +- } ++ if (CGROUP_BLKIO_WEIGHT_IS_OK(weight)) ++ return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range"); + + if (mode != UNIT_CHECK) { +- c->startup_blockio_weight = ul; ++ c->startup_blockio_weight = weight; + u->cgroup_realized_mask &= ~CGROUP_BLKIO; +- unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul); ++ ++ if (weight == CGROUP_BLKIO_WEIGHT_INVALID) ++ unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight="); ++ else ++ unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight); + } + + return 1; +@@ -455,17 +429,16 @@ int bus_cgroup_set_property( + + } else if (streq(name, "BlockIODeviceWeight")) { + const char *path; +- uint64_t u64; ++ uint64_t weight; + unsigned n = 0; + + r = sd_bus_message_enter_container(message, 'a', "(st)"); + if (r < 0) + return r; + +- while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) { +- unsigned long ul = u64; ++ while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) { + +- if (ul < 10 || ul > 1000) ++ if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID) + return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range"); + + if (mode != UNIT_CHECK) { +@@ -491,7 +464,7 @@ int bus_cgroup_set_property( + LIST_PREPEND(device_weights,c->blockio_device_weights, a); + } + +- a->weight = ul; ++ a->weight = weight; + } + + n++; +@@ -520,7 +493,7 @@ int bus_cgroup_set_property( + + fputs("BlockIODeviceWeight=\n", f); + LIST_FOREACH(device_weights, a, c->blockio_device_weights) +- fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight); ++ fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight); + + fflush(f); + unit_write_drop_in_private(u, mode, name, buf); +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index a10e1903a..da58bcc5c 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -2951,26 +2951,19 @@ int config_parse_cpu_shares( + void *data, + void *userdata) { + +- unsigned long *shares = data, lu; ++ uint64_t *shares = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + +- if (isempty(rvalue)) { +- *shares = (unsigned long) -1; +- return 0; +- } +- +- r = safe_atolu(rvalue, &lu); +- if (r < 0 || lu <= 0) { +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, +- "CPU shares '%s' invalid. Ignoring.", rvalue); ++ r = cg_cpu_shares_parse(rvalue, shares); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue); + return 0; + } + +- *shares = lu; + return 0; + } + +@@ -3163,26 +3156,19 @@ int config_parse_blockio_weight( + void *data, + void *userdata) { + +- unsigned long *weight = data, lu; ++ uint64_t *weight = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + +- if (isempty(rvalue)) { +- *weight = (unsigned long) -1; +- return 0; +- } +- +- r = safe_atolu(rvalue, &lu); +- if (r < 0 || lu < 10 || lu > 1000) { +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, +- "Block IO weight '%s' invalid. Ignoring.", rvalue); ++ r = cg_blkio_weight_parse(rvalue, weight); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue); + return 0; + } + +- *weight = lu; + return 0; + } + +@@ -3201,8 +3187,8 @@ int config_parse_blockio_device_weight( + _cleanup_free_ char *path = NULL; + CGroupBlockIODeviceWeight *w; + CGroupContext *c = data; +- unsigned long lu; + const char *weight; ++ uint64_t u; + size_t n; + int r; + +@@ -3219,9 +3205,10 @@ int config_parse_blockio_device_weight( + + n = strcspn(rvalue, WHITESPACE); + weight = rvalue + n; +- if (!*weight) { +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, +- "Expected block device and device weight. Ignoring."); ++ weight += strspn(weight, WHITESPACE); ++ ++ if (isempty(weight)) { ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring."); + return 0; + } + +@@ -3230,19 +3217,18 @@ int config_parse_blockio_device_weight( + return log_oom(); + + if (!path_startswith(path, "/dev")) { +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, +- "Invalid device node path '%s'. Ignoring.", path); ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path); + return 0; + } + +- weight += strspn(weight, WHITESPACE); +- r = safe_atolu(weight, &lu); +- if (r < 0 || lu < 10 || lu > 1000) { +- log_syntax(unit, LOG_ERR, filename, line, EINVAL, +- "Block IO weight '%s' invalid. Ignoring.", rvalue); ++ r = cg_blkio_weight_parse(weight, &u); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight); + return 0; + } + ++ assert(u != CGROUP_BLKIO_WEIGHT_INVALID); ++ + w = new0(CGroupBlockIODeviceWeight, 1); + if (!w) + return log_oom(); +@@ -3250,7 +3236,7 @@ int config_parse_blockio_device_weight( + w->path = path; + path = NULL; + +- w->weight = lu; ++ w->weight = u; + + LIST_PREPEND(device_weights, c->blockio_device_weights, w); + return 0; +diff --git a/src/core/unit.c b/src/core/unit.c +index 6a2ad6ed3..8c0fde878 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -1178,8 +1178,8 @@ static int unit_add_startup_units(Unit *u) { + if (!c) + return 0; + +- if (c->startup_cpu_shares == (unsigned long) -1 && +- c->startup_blockio_weight == (unsigned long) -1) ++ if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID && ++ c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID) + return 0; + + r = set_put(u->manager->startup_units, u); +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index 263457427..cbf1eccf7 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -23,20 +23,23 @@ + + #include "sd-daemon.h" + #include "sd-event.h" +-#include "util.h" +-#include "strv.h" +-#include "macro.h" ++#include "sd-bus.h" ++ ++#include "bus-error.h" ++#include "bus-internal.h" ++#include "bus-label.h" ++#include "bus-message.h" ++#include "cgroup-util.h" + #include "def.h" +-#include "path-util.h" ++#include "macro.h" + #include "missing.h" ++#include "path-util.h" + #include "set.h" ++#include "strv.h" + #include "unit-name.h" ++#include "util.h" + +-#include "sd-bus.h" +-#include "bus-error.h" +-#include "bus-message.h" + #include "bus-util.h" +-#include "bus-internal.h" + + static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + sd_event *e = userdata; +@@ -1429,10 +1432,22 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + } + + r = sd_bus_message_append(m, "sv", "TasksMax", "t", t); +- } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) { ++ ++ } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) { ++ uint64_t u; ++ ++ r = cg_cpu_shares_parse(eq, &u); ++ if (r < 0) { ++ log_error("Failed to parse %s value %s.", field, eq); ++ return -EINVAL; ++ } ++ ++ r = sd_bus_message_append(m, "v", "t", u); ++ ++ } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) { + uint64_t u; + +- r = safe_atou64(eq, &u); ++ r = cg_blkio_weight_parse(eq, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index c5d9e4bb5..f67b53b4d 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -1795,3 +1795,44 @@ int cg_kernel_controllers(Set *controllers) { + + return 0; + } ++ ++ ++int cg_cpu_shares_parse(const char *s, uint64_t *ret) { ++ uint64_t u; ++ int r; ++ ++ if (isempty(s)) { ++ *ret = CGROUP_CPU_SHARES_INVALID; ++ return 0; ++ } ++ ++ r = safe_atou64(s, &u); ++ if (r < 0) ++ return r; ++ ++ if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX) ++ return -ERANGE; ++ ++ *ret = u; ++ return 0; ++} ++ ++int cg_blkio_weight_parse(const char *s, uint64_t *ret) { ++ uint64_t u; ++ int r; ++ ++ if (isempty(s)) { ++ *ret = CGROUP_BLKIO_WEIGHT_INVALID; ++ return 0; ++ } ++ ++ r = safe_atou64(s, &u); ++ if (r < 0) ++ return r; ++ ++ if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX) ++ return -ERANGE; ++ ++ *ret = u; ++ return 0; ++} +diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h +index 31bd8d311..615c1f03e 100644 +--- a/src/shared/cgroup-util.h ++++ b/src/shared/cgroup-util.h +@@ -39,6 +39,30 @@ typedef enum CGroupControllerMask { + _CGROUP_CONTROLLER_MASK_ALL = 31 + } CGroupControllerMask; + ++/* Special values for the cpu.shares attribute */ ++#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1) ++#define CGROUP_CPU_SHARES_MIN UINT64_C(2) ++#define CGROUP_CPU_SHARES_MAX UINT64_C(262144) ++#define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024) ++ ++static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) { ++ return ++ x == CGROUP_CPU_SHARES_INVALID || ++ (x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX); ++} ++ ++/* Special values for the blkio.weight attribute */ ++#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1) ++#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10) ++#define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000) ++#define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500) ++ ++static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) { ++ return ++ x == CGROUP_BLKIO_WEIGHT_INVALID || ++ (x >= CGROUP_BLKIO_WEIGHT_MIN && x <= CGROUP_BLKIO_WEIGHT_MAX); ++} ++ + /* + * General rules: + * +@@ -136,3 +160,6 @@ int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool de + CGroupControllerMask cg_mask_supported(void); + + int cg_kernel_controllers(Set *controllers); ++ ++int cg_cpu_shares_parse(const char *s, uint64_t *ret); ++int cg_blkio_weight_parse(const char *s, uint64_t *ret); diff --git a/SOURCES/0579-fileio-add-new-helper-call-read_line-as-bounded-getl.patch b/SOURCES/0579-fileio-add-new-helper-call-read_line-as-bounded-getl.patch new file mode 100644 index 0000000..a12c7ab --- /dev/null +++ b/SOURCES/0579-fileio-add-new-helper-call-read_line-as-bounded-getl.patch @@ -0,0 +1,177 @@ +From d7b56e186521ce2e48e27edda121d780a3d62d27 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 23 Nov 2017 08:53:50 +0100 +Subject: [PATCH] fileio: add new helper call read_line() as bounded getline() + replacement + +read_line() is much like getline(), and returns a line read from a +FILE*, of arbitrary sizes. In contrast to gets() it will grow the buffer +dynamically, and in contrast to getline() it will place a user-specified +boundary on the line. + +(cherry-picked from commit 4f9a66a32dda1d9a28f9bb3fa31c2148524bc46a) + +Resolves: #1503106 +--- + src/shared/fileio.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++ + src/shared/fileio.h | 2 ++ + src/test/test-fileio.c | 44 +++++++++++++++++++++++++++++ + 3 files changed, 123 insertions(+) + +diff --git a/src/shared/fileio.c b/src/shared/fileio.c +index ff6b1a7ed..107737573 100644 +--- a/src/shared/fileio.c ++++ b/src/shared/fileio.c +@@ -815,3 +815,80 @@ int get_status_field(const char *filename, const char *pattern, char **field) { + + return 0; + } ++ ++int read_line(FILE *f, size_t limit, char **ret) { ++ _cleanup_free_ char *buffer = NULL; ++ size_t n = 0, allocated = 0, count = 0; ++ int r; ++ ++ assert(f); ++ ++ /* Something like a bounded version of getline(). ++ * ++ * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string ++ * returned. ++ * ++ * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from ++ * the number of characters in the returned string). When EOF is hit, 0 is returned. ++ * ++ * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding ++ * delimiters. If the limit is hit we fail and return -ENOBUFS. ++ * ++ * If a line shall be skipped ret may be initialized as NULL. */ ++ ++ if (ret) { ++ if (!GREEDY_REALLOC(buffer, allocated, 1)) ++ return -ENOMEM; ++ } ++ ++ flockfile(f); ++ ++ for (;;) { ++ int c; ++ ++ if (n >= limit) { ++ funlockfile(f); ++ return -ENOBUFS; ++ } ++ ++ errno = 0; ++ c = fgetc_unlocked(f); ++ if (c == EOF) { ++ /* if we read an error, and have no data to return, then propagate the error */ ++ if (ferror_unlocked(f) && n == 0) { ++ r = errno > 0 ? -errno : -EIO; ++ funlockfile(f); ++ return r; ++ } ++ ++ break; ++ } ++ ++ count++; ++ ++ if (IN_SET(c, '\n', 0)) /* Reached a delimiter */ ++ break; ++ ++ if (ret) { ++ if (!GREEDY_REALLOC(buffer, allocated, n + 2)) { ++ funlockfile(f); ++ return -ENOMEM; ++ } ++ ++ buffer[n] = (char) c; ++ } ++ ++ n++; ++ } ++ ++ funlockfile(f); ++ ++ if (ret) { ++ buffer[n] = 0; ++ ++ *ret = buffer; ++ buffer = NULL; ++ } ++ ++ return (int) count; ++} +diff --git a/src/shared/fileio.h b/src/shared/fileio.h +index 5ae51c1e2..f33464dce 100644 +--- a/src/shared/fileio.h ++++ b/src/shared/fileio.h +@@ -43,3 +43,5 @@ int write_env_file(const char *fname, char **l); + int executable_is_script(const char *path, char **interpreter); + + int get_status_field(const char *filename, const char *pattern, char **field); ++ ++int read_line(FILE *f, size_t limit, char **ret); +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index 63e4a19b7..fc5969322 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -392,6 +392,49 @@ static void test_load_env_file_pairs(void) { + unlink(fn); + } + ++static void test_read_line(void) { ++ _cleanup_fclose_ FILE *f = NULL; ++ _cleanup_free_ char *line = NULL; ++ ++ char buffer[] = ++ "Some test data\n" ++ "With newlines, and a NUL byte\0" ++ "\n" ++ "an empty line\n" ++ "an ignored line\n" ++ "and a very long line that is supposed to be truncated, because it is so long\n"; ++ ++ f = fmemopen(buffer, sizeof(buffer), "re"); ++ assert_se(f); ++ ++ assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data")); ++ line = mfree(line); ++ ++ assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte")); ++ line = mfree(line); ++ ++ assert_se(read_line(f, 1024, &line) == 1 && streq(line, "")); ++ line = mfree(line); ++ ++ assert_se(read_line(f, 1024, &line) == 14 && streq(line, "an empty line")); ++ line = mfree(line); ++ ++ assert_se(read_line(f, (size_t) -1, NULL) == 16); ++ ++ assert_se(read_line(f, 16, &line) == -ENOBUFS); ++ line = mfree(line); ++ ++ /* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first ++ * character after the previous limit. Let's make use of tha to continue our test. */ ++ assert_se(read_line(f, 1024, &line) == 61 && streq(line, "line that is supposed to be truncated, because it is so long")); ++ line = mfree(line); ++ ++ assert_se(read_line(f, 1024, &line) == 1 && streq(line, "")); ++ line = mfree(line); ++ ++ assert_se(read_line(f, 1024, &line) == 0 && streq(line, "")); ++} ++ + int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); +@@ -405,6 +448,7 @@ int main(int argc, char *argv[]) { + test_write_string_file(); + test_write_string_file_no_create(); + test_load_env_file_pairs(); ++ test_read_line(); + + return 0; + } diff --git a/SOURCES/0580-def-add-new-constant-LONG_LINE_MAX.patch b/SOURCES/0580-def-add-new-constant-LONG_LINE_MAX.patch new file mode 100644 index 0000000..2798123 --- /dev/null +++ b/SOURCES/0580-def-add-new-constant-LONG_LINE_MAX.patch @@ -0,0 +1,28 @@ +From 4cd343cf1a25e603ea78acbac027589f6a53a118 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 23 Nov 2017 09:22:21 +0100 +Subject: [PATCH] def: add new constant LONG_LINE_MAX + +LONG_LINE_MAX is much like LINE_MAX, but longer. + +As it turns out LINE_MAX at 4096 is too short for many usecases. Since +the general concept of having a common maximum line length limit makes +sense let's add our own, and make it larger (1MB for now). + +(cherry-picked from commit 189912440f6545404e84b3cd1d6ca54f1057e3e6) + +Resolves: #1503106 +--- + src/shared/def.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/shared/def.h b/src/shared/def.h +index 76daf012d..9e008a6d2 100644 +--- a/src/shared/def.h ++++ b/src/shared/def.h +@@ -87,3 +87,5 @@ + + #define NOTIFY_FD_MAX 768 + #define NOTIFY_BUFFER_MAX PIPE_BUF ++ ++#define LONG_LINE_MAX (1U*1024U*1024U) diff --git a/SOURCES/0581-fileio-rework-read_one_line_file-on-top-of-read_line.patch b/SOURCES/0581-fileio-rework-read_one_line_file-on-top-of-read_line.patch new file mode 100644 index 0000000..5be44af --- /dev/null +++ b/SOURCES/0581-fileio-rework-read_one_line_file-on-top-of-read_line.patch @@ -0,0 +1,55 @@ +From aab6aeb2529a1e9b51eeadf91decd06e03af5da1 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 23 Nov 2017 09:23:34 +0100 +Subject: [PATCH] fileio: rework read_one_line_file() on top of read_line() + +(cherry picked from commit f4b51a2d092685c9a080e84130fec2d74c834f5c) + +Resolves: #1503106 +--- + src/shared/fileio.c | 18 ++---------------- + 1 file changed, 2 insertions(+), 16 deletions(-) + +diff --git a/src/shared/fileio.c b/src/shared/fileio.c +index 107737573..be775f982 100644 +--- a/src/shared/fileio.c ++++ b/src/shared/fileio.c +@@ -25,6 +25,7 @@ + #include "strv.h" + #include "utf8.h" + #include "ctype.h" ++#include "def.h" + #include "fileio.h" + + int write_string_stream(FILE *f, const char *line) { +@@ -108,7 +109,6 @@ int write_string_file_atomic(const char *fn, const char *line) { + + int read_one_line_file(const char *fn, char **line) { + _cleanup_fclose_ FILE *f = NULL; +- char t[LINE_MAX], *c; + + assert(fn); + assert(line); +@@ -117,21 +117,7 @@ int read_one_line_file(const char *fn, char **line) { + if (!f) + return -errno; + +- if (!fgets(t, sizeof(t), f)) { +- +- if (ferror(f)) +- return errno ? -errno : -EIO; +- +- t[0] = 0; +- } +- +- c = strdup(t); +- if (!c) +- return -ENOMEM; +- truncate_nl(c); +- +- *line = c; +- return 0; ++ return read_line(f, LONG_LINE_MAX, line); + } + + int read_full_stream(FILE *f, char **contents, size_t *size) { diff --git a/SOURCES/0582-cgroup-util-replace-one-use-of-fgets-by-read_line.patch b/SOURCES/0582-cgroup-util-replace-one-use-of-fgets-by-read_line.patch new file mode 100644 index 0000000..fa3a207 --- /dev/null +++ b/SOURCES/0582-cgroup-util-replace-one-use-of-fgets-by-read_line.patch @@ -0,0 +1,33 @@ +From cde797e980fac7f8b1aa35db3f65fc591b820d62 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 23 Nov 2017 09:27:06 +0100 +Subject: [PATCH] cgroup-util: replace one use of fgets() by read_line() + +(cherry picked from commit 2351e44d3ed57b7a48b9e544a59c3b797ac4d216) + +Resolves: #1503106 +--- + src/shared/cgroup-util.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c +index f67b53b4d..4585450b3 100644 +--- a/src/shared/cgroup-util.c ++++ b/src/shared/cgroup-util.c +@@ -1747,7 +1747,6 @@ CGroupControllerMask cg_mask_supported(void) { + + int cg_kernel_controllers(Set *controllers) { + _cleanup_fclose_ FILE *f = NULL; +- char buf[LINE_MAX]; + int r; + + assert(controllers); +@@ -1760,7 +1759,7 @@ int cg_kernel_controllers(Set *controllers) { + } + + /* Ignore the header line */ +- (void) fgets(buf, sizeof(buf), f); ++ (void) read_line(f, (size_t) -1, NULL); + + for (;;) { + char *controller; diff --git a/SOURCES/0583-conf-parse-remove-4K-line-length-limit.patch b/SOURCES/0583-conf-parse-remove-4K-line-length-limit.patch new file mode 100644 index 0000000..14853bf --- /dev/null +++ b/SOURCES/0583-conf-parse-remove-4K-line-length-limit.patch @@ -0,0 +1,124 @@ +From beef22775206d99b06c95c9a015e1b17bf3e767f Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 23 Nov 2017 10:13:52 +0100 +Subject: [PATCH] conf-parse: remove 4K line length limit + +Let's use read_line() to solve our long line limitation. + +Fixes #3302. +(cherry picked from commit e6dde451a51dc5aaa7f4d98d39b8fe735f73d2af) + +Resolves: #1503106 +--- + src/shared/conf-parser.c | 50 +++++++++++++++++++++++++++++++++++------------- + src/shared/utf8.h | 1 + + 2 files changed, 38 insertions(+), 13 deletions(-) + +diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c +index 0b1af6c57..73e4d49ea 100644 +--- a/src/shared/conf-parser.c ++++ b/src/shared/conf-parser.c +@@ -28,6 +28,8 @@ + + #include "conf-parser.h" + #include "conf-files.h" ++#include "def.h" ++#include "fileio.h" + #include "util.h" + #include "macro.h" + #include "strv.h" +@@ -339,7 +341,7 @@ int config_parse(const char *unit, + _cleanup_free_ char *section = NULL, *continuation = NULL; + _cleanup_fclose_ FILE *ours = NULL; + unsigned line = 0, section_line = 0; +- bool section_ignored = false; ++ bool section_ignored = false, allow_bom = true; + int r; + + assert(filename); +@@ -359,21 +361,45 @@ int config_parse(const char *unit, + + fd_warn_permissions(filename, fileno(f)); + +- while (!feof(f)) { +- char l[LINE_MAX], *p, *c = NULL, *e; ++ for (;;) { ++ _cleanup_free_ char *buf = NULL; ++ char *l, *p, *c = NULL, *e; + bool escaped = false; + +- if (!fgets(l, sizeof(l), f)) { +- if (feof(f)) +- break; ++ r = read_line(f, LONG_LINE_MAX, &buf); ++ if (r == 0) ++ break; ++ if (r == -ENOBUFS) { ++ if (warn) ++ log_error_errno(r, "%s:%u: Line too long", filename, line); + +- log_error_errno(errno, "Failed to read configuration file '%s': %m", filename); +- return -errno; ++ return r; ++ } ++ if (r < 0) { ++ if (warn) ++ log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line); ++ ++ return r; + } + +- truncate_nl(l); ++ l = buf; ++ if (allow_bom) { ++ char *q; ++ ++ q = startswith(buf, UTF8_BYTE_ORDER_MARK); ++ if (q) { ++ l = q; ++ allow_bom = false; ++ } ++ } + + if (continuation) { ++ if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) { ++ if (warn) ++ log_error("%s:%u: Continuation line too long", filename, line); ++ return -ENOBUFS; ++ } ++ + c = strappend(continuation, l); + if (!c) { + if (warn) +@@ -381,8 +407,7 @@ int config_parse(const char *unit, + return -ENOMEM; + } + +- free(continuation); +- continuation = NULL; ++ continuation = mfree(continuation); + p = c; + } else + p = l; +@@ -428,8 +453,7 @@ int config_parse(const char *unit, + + if (r < 0) { + if (warn) +- log_warning_errno(r, "Failed to parse file '%s': %m", +- filename); ++ log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line); + return r; + } + } +diff --git a/src/shared/utf8.h b/src/shared/utf8.h +index 77f663438..d31737061 100644 +--- a/src/shared/utf8.h ++++ b/src/shared/utf8.h +@@ -26,6 +26,7 @@ + #include "macro.h" + + #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" ++#define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf" + + const char *utf8_is_valid(const char *s) _pure_; + char *ascii_is_valid(const char *s) _pure_; diff --git a/SOURCES/0584-test-conf-parser-add-tests-for-config-parser.patch b/SOURCES/0584-test-conf-parser-add-tests-for-config-parser.patch new file mode 100644 index 0000000..1ee34f3 --- /dev/null +++ b/SOURCES/0584-test-conf-parser-add-tests-for-config-parser.patch @@ -0,0 +1,204 @@ +From 75fa3b2c5f62dd6d55860aaea979289d53b62a24 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 23 Nov 2017 09:58:11 +0100 +Subject: [PATCH] test-conf-parser: add tests for config parser + +Add some basic tests for config_parse(). Add tests for the new long lines, +including overflow. + +(cherry picked from commit e3f46367f577f8bd4b3a62ea0149bdcb112da573) +(cherry picked from commit 8f313f4febb4df13279aaae86c846bbb142a5a39) + +Resolves: #1503106 +--- + Makefile.am | 7 ++ + src/test/test-conf-parser.c | 155 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 162 insertions(+) + create mode 100644 src/test/test-conf-parser.c + +diff --git a/Makefile.am b/Makefile.am +index c4a96e1fd..8c73326fa 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1416,6 +1416,7 @@ tests += \ + test-socket-util \ + test-fdset \ + test-conf-files \ ++ test-conf-parser \ + test-capability \ + test-async \ + test-ratelimit \ +@@ -2041,6 +2042,12 @@ test_conf_files_SOURCES = \ + test_conf_files_LDADD = \ + libsystemd-shared.la + ++test_conf_parser_SOURCES = \ ++ src/test/test-conf-parser.c ++ ++test_conf_parser_LDADD = \ ++ libsystemd-shared.la ++ + # ------------------------------------------------------------------------------ + ## .PHONY so it always rebuilds it + .PHONY: coverage lcov-run lcov-report coverage-sync +diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c +new file mode 100644 +index 000000000..4052d0095 +--- /dev/null ++++ b/src/test/test-conf-parser.c +@@ -0,0 +1,155 @@ ++/*** ++ This file is part of systemd. ++ ++ Copyright 2015 Ronny Chevalier ++ ++ 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 "conf-parser.h" ++#include "fileio.h" ++#include "log.h" ++#include "macro.h" ++#include "strv.h" ++#include "util.h" ++ ++#define x10(x) x x x x x x x x x x ++#define x100(x) x10(x10(x)) ++#define x1000(x) x10(x100(x)) ++ ++static const char* const config_file[] = { ++ "[Section]\n" ++ "setting1=1\n", ++ ++ "[Section]\n" ++ "setting1=1", /* no terminating newline */ ++ ++ "\n\n\n\n[Section]\n\n\n" ++ "setting1=1", /* some whitespace, no terminating newline */ ++ ++ "[Section]\n" ++ "[Section]\n" ++ "setting1=1\n" ++ "setting1=2\n" ++ "setting1=1\n", /* repeated settings */ ++ ++ "[Section]\n" ++ "setting1=1\\\n" /* normal continuation */ ++ "2\\\n" ++ "3\n", ++ ++ "[Section]\n" ++ "setting1=1\\\\\\\n" /* continuation with trailing escape symbols */ ++ "\\\\2\n", /* note that C requires one level of escaping, so the ++ * parser gets "…1 BS BS BS NL BS BS 2 NL", which ++ * it translates into "…1 BS BS SP BS BS 2" */ ++ ++ "\n[Section]\n\n" ++ "setting1=" /* a line above LINE_MAX length */ ++ x1000("ABCD") ++ "\n", ++ ++ "[Section]\n" ++ "setting1=" /* a line above LINE_MAX length, with continuation */ ++ x1000("ABCD") "\\\n" ++ "foobar", ++ ++ "[Section]\n" ++ "setting1=" /* a line above the allowed limit: 9 + 1050000 + 1 */ ++ x1000(x1000("x") x10("abcde")) "\n", ++ ++ "[Section]\n" ++ "setting1=" /* many continuation lines, together above the limit */ ++ x1000(x1000("x") x10("abcde") "\\\n") "xxx", ++}; ++ ++static void test_config_parse(unsigned i, const char *s) { ++ char name[] = "/tmp/test-conf-parser.XXXXXX"; ++ int fd, r; ++ _cleanup_fclose_ FILE *f = NULL; ++ _cleanup_free_ char *setting1 = NULL; ++ ++ const ConfigTableItem items[] = { ++ { "Section", "setting1", config_parse_string, 0, &setting1}, ++ {} ++ }; ++ ++ log_info("== %s[%i] ==", __func__, i); ++ ++ fd = mkostemp_safe(name, O_CLOEXEC); ++ assert_se(fd >= 0); ++ assert_se((size_t) write(fd, s, strlen(s)) == strlen(s)); ++ ++ assert_se(lseek(fd, 0, SEEK_SET) == 0); ++ assert_se(f = fdopen(fd, "r")); ++ ++ /* ++ int config_parse(const char *unit, ++ const char *filename, ++ FILE *f, ++ const char *sections, ++ ConfigItemLookup lookup, ++ const void *table, ++ bool relaxed, ++ bool allow_include, ++ bool warn, ++ void *userdata) ++ */ ++ ++ r = config_parse(NULL, name, f, ++ "Section\0", ++ config_item_table_lookup, items, ++ false, false, true, NULL); ++ ++ switch (i) { ++ case 0 ... 3: ++ assert_se(r == 0); ++ assert_se(streq(setting1, "1")); ++ break; ++ ++ case 4: ++ assert_se(r == 0); ++ assert_se(streq(setting1, "1 2 3")); ++ break; ++ ++ case 5: ++ assert_se(r == 0); ++ assert_se(streq(setting1, "1\\\\ \\\\2")); ++ break; ++ ++ case 6: ++ assert_se(r == 0); ++ assert_se(streq(setting1, x1000("ABCD"))); ++ break; ++ ++ case 7: ++ assert_se(r == 0); ++ assert_se(streq(setting1, x1000("ABCD") " foobar")); ++ break; ++ ++ case 8 ... 9: ++ assert_se(r == -ENOBUFS); ++ assert_se(setting1 == NULL); ++ break; ++ } ++} ++ ++int main(int argc, char **argv) { ++ unsigned i; ++ ++ for (i = 0; i < ELEMENTSOF(config_file); i++) ++ test_config_parse(i, config_file[i]); ++ ++ return 0; ++} diff --git a/SOURCES/0585-fileio-use-_cleanup_-for-FILE-unlocking.patch b/SOURCES/0585-fileio-use-_cleanup_-for-FILE-unlocking.patch new file mode 100644 index 0000000..726ccaf --- /dev/null +++ b/SOURCES/0585-fileio-use-_cleanup_-for-FILE-unlocking.patch @@ -0,0 +1,103 @@ +From d750826683aaad1cf33b16290c7daa8b0a669f4c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 23 Sep 2017 10:48:09 +0200 +Subject: [PATCH] fileio: use _cleanup_ for FILE unlocking + +(cherry picked from commit f858e5148e4f36335555dfaac812197ebd3ef036) + +Resolves: #1503106 +--- + src/shared/fileio.c | 57 +++++++++++++++++++++++++---------------------------- + 1 file changed, 27 insertions(+), 30 deletions(-) + +diff --git a/src/shared/fileio.c b/src/shared/fileio.c +index be775f982..4880a4941 100644 +--- a/src/shared/fileio.c ++++ b/src/shared/fileio.c +@@ -802,10 +802,13 @@ int get_status_field(const char *filename, const char *pattern, char **field) { + return 0; + } + ++static inline void funlockfilep(FILE **f) { ++ funlockfile(*f); ++} ++ + int read_line(FILE *f, size_t limit, char **ret) { + _cleanup_free_ char *buffer = NULL; + size_t n = 0, allocated = 0, count = 0; +- int r; + + assert(f); + +@@ -827,48 +830,42 @@ int read_line(FILE *f, size_t limit, char **ret) { + return -ENOMEM; + } + +- flockfile(f); ++ { ++ _cleanup_(funlockfilep) FILE *flocked = f; ++ flockfile(f); + +- for (;;) { +- int c; ++ for (;;) { ++ int c; + +- if (n >= limit) { +- funlockfile(f); +- return -ENOBUFS; +- } ++ if (n >= limit) ++ return -ENOBUFS; ++ ++ errno = 0; ++ c = fgetc_unlocked(f); ++ if (c == EOF) { ++ /* if we read an error, and have no data to return, then propagate the error */ ++ if (ferror_unlocked(f) && n == 0) ++ return errno > 0 ? -errno : -EIO; + +- errno = 0; +- c = fgetc_unlocked(f); +- if (c == EOF) { +- /* if we read an error, and have no data to return, then propagate the error */ +- if (ferror_unlocked(f) && n == 0) { +- r = errno > 0 ? -errno : -EIO; +- funlockfile(f); +- return r; ++ break; + } + +- break; +- } ++ count++; + +- count++; ++ if (IN_SET(c, '\n', 0)) /* Reached a delimiter */ ++ break; + +- if (IN_SET(c, '\n', 0)) /* Reached a delimiter */ +- break; ++ if (ret) { ++ if (!GREEDY_REALLOC(buffer, allocated, n + 2)) ++ return -ENOMEM; + +- if (ret) { +- if (!GREEDY_REALLOC(buffer, allocated, n + 2)) { +- funlockfile(f); +- return -ENOMEM; ++ buffer[n] = (char) c; + } + +- buffer[n] = (char) c; ++ n++; + } +- +- n++; + } + +- funlockfile(f); +- + if (ret) { + buffer[n] = 0; + diff --git a/SOURCES/0586-test-fileio-also-test-read_line-with-actual-files.patch b/SOURCES/0586-test-fileio-also-test-read_line-with-actual-files.patch new file mode 100644 index 0000000..b89c611 --- /dev/null +++ b/SOURCES/0586-test-fileio-also-test-read_line-with-actual-files.patch @@ -0,0 +1,105 @@ +From 4a0e2c447eeac47eaa497a2db6925590b3cec3bd Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Thu, 23 Nov 2017 11:42:05 +0100 +Subject: [PATCH] test-fileio: also test read_line() with actual files + +Just in case the real FILE and the one from fmemopen weren't exactly +the same. + +(cherry picked from commit 2c9de13912350f5887ccccdae9e1707512208053) + +Resolves: #1503106 +--- + src/test/test-fileio.c | 63 ++++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 51 insertions(+), 12 deletions(-) + +diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c +index fc5969322..791bfc97b 100644 +--- a/src/test/test-fileio.c ++++ b/src/test/test-fileio.c +@@ -392,20 +392,17 @@ static void test_load_env_file_pairs(void) { + unlink(fn); + } + +-static void test_read_line(void) { +- _cleanup_fclose_ FILE *f = NULL; +- _cleanup_free_ char *line = NULL; + +- char buffer[] = +- "Some test data\n" +- "With newlines, and a NUL byte\0" +- "\n" +- "an empty line\n" +- "an ignored line\n" +- "and a very long line that is supposed to be truncated, because it is so long\n"; ++static const char buffer[] = ++ "Some test data\n" ++ "With newlines, and a NUL byte\0" ++ "\n" ++ "an empty line\n" ++ "an ignored line\n" ++ "and a very long line that is supposed to be truncated, because it is so long\n"; + +- f = fmemopen(buffer, sizeof(buffer), "re"); +- assert_se(f); ++static void test_read_line_one_file(FILE *f) { ++ _cleanup_free_ char *line = NULL; + + assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data")); + line = mfree(line); +@@ -435,6 +432,46 @@ static void test_read_line(void) { + assert_se(read_line(f, 1024, &line) == 0 && streq(line, "")); + } + ++static void test_read_line(void) { ++ _cleanup_fclose_ FILE *f = NULL; ++ _cleanup_free_ char *line = NULL; ++ ++ f = fmemopen((void*) buffer, sizeof(buffer), "re"); ++ assert_se(f); ++ ++ test_read_line_one_file(f); ++} ++ ++static void test_read_line2(void) { ++ char name[] = "/tmp/test-fileio.XXXXXX"; ++ int fd; ++ _cleanup_fclose_ FILE *f = NULL; ++ ++ fd = mkostemp_safe(name, O_CLOEXEC); ++ assert_se(fd >= 0); ++ assert_se((size_t) write(fd, buffer, sizeof(buffer)) == sizeof(buffer)); ++ ++ assert_se(lseek(fd, 0, SEEK_SET) == 0); ++ assert_se(f = fdopen(fd, "r")); ++ ++ test_read_line_one_file(f); ++} ++ ++static void test_read_line3(void) { ++ _cleanup_fclose_ FILE *f = NULL; ++ _cleanup_free_ char *line = NULL; ++ int r; ++ ++ f = fopen("/proc/cmdline", "re"); ++ if (!f && IN_SET(errno, ENOENT, EPERM)) ++ return; ++ assert_se(f); ++ ++ r = read_line(f, LINE_MAX, &line); ++ assert_se((size_t) r == strlen(line) + 1); ++ assert_se(read_line(f, LINE_MAX, NULL) == 0); ++} ++ + int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); +@@ -449,6 +486,8 @@ int main(int argc, char *argv[]) { + test_write_string_file_no_create(); + test_load_env_file_pairs(); + test_read_line(); ++ test_read_line2(); ++ test_read_line3(); + + return 0; + } diff --git a/SOURCES/0587-fileio-return-0-from-read_one_line_file-on-success.patch b/SOURCES/0587-fileio-return-0-from-read_one_line_file-on-success.patch new file mode 100644 index 0000000..35fdb0b --- /dev/null +++ b/SOURCES/0587-fileio-return-0-from-read_one_line_file-on-success.patch @@ -0,0 +1,36 @@ +From 29d296bbe3ce769d64f90a08ba0e091725140704 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 24 Sep 2017 14:27:21 +0200 +Subject: [PATCH] fileio: return 0 from read_one_line_file on success + +Fixup for f4b51a2d09. Suggested by Evgeny Vereshchagin. + +(cherry picked from commit 2e33df93dee35af986683d1226f93e0f9659de5d) + +Resolves: #1503106 +--- + src/shared/fileio.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/shared/fileio.c b/src/shared/fileio.c +index 4880a4941..65a0753c2 100644 +--- a/src/shared/fileio.c ++++ b/src/shared/fileio.c +@@ -109,6 +109,7 @@ int write_string_file_atomic(const char *fn, const char *line) { + + int read_one_line_file(const char *fn, char **line) { + _cleanup_fclose_ FILE *f = NULL; ++ int r; + + assert(fn); + assert(line); +@@ -117,7 +118,8 @@ int read_one_line_file(const char *fn, char **line) { + if (!f) + return -errno; + +- return read_line(f, LONG_LINE_MAX, line); ++ r = read_line(f, LONG_LINE_MAX, line); ++ return r < 0 ? r : 0; + } + + int read_full_stream(FILE *f, char **contents, size_t *size) { diff --git a/SOURCES/0588-man-fix-description-of-force-in-halt-8-7392.patch b/SOURCES/0588-man-fix-description-of-force-in-halt-8-7392.patch new file mode 100644 index 0000000..c6309e0 --- /dev/null +++ b/SOURCES/0588-man-fix-description-of-force-in-halt-8-7392.patch @@ -0,0 +1,33 @@ +From fa011f2b4e6339f6672835712cb7b281e0603207 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Mon, 20 Nov 2017 14:27:46 +0100 +Subject: [PATCH] man: fix description of --force in halt(8) (#7392) + +https://bugzilla.redhat.com/show_bug.cgi?id=1449751 +(cherry picked from commit 5d9adb5b60b815b477ba9e6b19ef0fd7e1854a38) + +Resolves: #1515130 +--- + man/halt.xml | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/man/halt.xml b/man/halt.xml +index a06dbd009..d0fc25c20 100644 +--- a/man/halt.xml ++++ b/man/halt.xml +@@ -112,8 +112,13 @@ + + + +- Force immediate halt, power-off, reboot. Do +- not contact the init system. ++ Force immediate halt, power-off, or reboot. When ++ specified once, this results in an immediate but clean shutdown ++ by the system manager. When specified twice, this results in an ++ immediate shutdown without contacting the system manager. See the ++ description of in ++ systemctl1 ++ for more details. + + + diff --git a/SOURCES/0589-journal-return-better-error-for-empty-files.patch b/SOURCES/0589-journal-return-better-error-for-empty-files.patch new file mode 100644 index 0000000..8210792 --- /dev/null +++ b/SOURCES/0589-journal-return-better-error-for-empty-files.patch @@ -0,0 +1,32 @@ +From fcef41057f40008693dd9161c973c2c6117e1433 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sun, 25 Oct 2015 00:09:44 -0400 +Subject: [PATCH] journal: return better error for empty files + +When reading stuff, we should only return EIO when an actual read error +occured, not when we don't like the data for whatever reason. + +We already return ENODATA for all other kinds of file truncation, hence +do the same for the most obvious kind, so that callers know what ENODATA +means. + +(cherry picked from commit cfb571f30fd415304b2f674f1615dc861058c347) + +Related: #1465759 +--- + src/journal/journal-file.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index ebc8e6230..2bb3a9757 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -2693,7 +2693,7 @@ int journal_file_open( + } + + if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) { +- r = -EIO; ++ r = -ENODATA; + goto fail; + } + diff --git a/SOURCES/0590-journalctl-continue-operation-even-if-we-run-into-an.patch b/SOURCES/0590-journalctl-continue-operation-even-if-we-run-into-an.patch new file mode 100644 index 0000000..e2c0f6f --- /dev/null +++ b/SOURCES/0590-journalctl-continue-operation-even-if-we-run-into-an.patch @@ -0,0 +1,35 @@ +From d5a96e0d5fccfa2f0c31df4ef5637717acd1fa9d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Nov 2015 23:13:01 +0100 +Subject: [PATCH] journalctl: continue operation, even if we run into an + invalid file + +(cherry picked from commit 4f52b822b05c373f40fea1a41ae3ade5d5ff558e) + +Related: #1465759 +--- + src/journal/journalctl.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index c771cff8b..8c8379732 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1804,15 +1804,12 @@ static int access_check(sd_journal *j) { + SET_FOREACH(code, j->errors, it) { + int err; + +- err = -PTR_TO_INT(code); +- assert(err > 0); ++ err = abs(PTR_TO_INT(code)); + + if (err == EACCES) + continue; + +- log_warning_errno(err, "Error was encountered while opening journal files: %m"); +- if (r == 0) +- r = -err; ++ log_warning_errno(err, "An error was encountered while opening journal files, ignoring: %m"); + } + + return r; diff --git a/SOURCES/0591-journal-remove-error-check-that-never-happens.patch b/SOURCES/0591-journal-remove-error-check-that-never-happens.patch new file mode 100644 index 0000000..1e8f057 --- /dev/null +++ b/SOURCES/0591-journal-remove-error-check-that-never-happens.patch @@ -0,0 +1,53 @@ +From 2b7119bc5e1a62d1bb6cb6ac0e4239345b9f8691 Mon Sep 17 00:00:00 2001 +From: Thomas Hindoe Paaboel Andersen +Date: Fri, 14 Aug 2015 23:40:27 +0200 +Subject: [PATCH] journal: remove error check that never happens + +remove_directory will always return 0 so this can never happen. +Besides that, d->path and d are freed so we would end up with +a null pointer dereference anyway. + +(cherry picked from commit b2b46f91dbb71676cb981907c68521e4b1e80af1) + +Related: #1465759 +--- + src/journal/sd-journal.c | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 72f312b67..3749f9e89 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -1487,7 +1487,7 @@ static int add_root_directory(sd_journal *j, const char *p) { + return 0; + } + +-static int remove_directory(sd_journal *j, Directory *d) { ++static void remove_directory(sd_journal *j, Directory *d) { + assert(j); + + if (d->wd > 0) { +@@ -1506,8 +1506,6 @@ static int remove_directory(sd_journal *j, Directory *d) { + + free(d->path); + free(d); +- +- return 0; + } + + static int add_search_paths(sd_journal *j) { +@@ -2145,12 +2143,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { + + /* Event for a subdirectory */ + +- if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) { +- r = remove_directory(j, d); +- if (r < 0) +- log_debug_errno(r, "Failed to remove directory %s: %m", d->path); +- } +- ++ if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) ++ remove_directory(j, d); + + } else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) { + diff --git a/SOURCES/0592-sd-journal-various-clean-ups-and-modernizations.patch b/SOURCES/0592-sd-journal-various-clean-ups-and-modernizations.patch new file mode 100644 index 0000000..fb8c700 --- /dev/null +++ b/SOURCES/0592-sd-journal-various-clean-ups-and-modernizations.patch @@ -0,0 +1,503 @@ +From 6930375c3f0d9681f27b42f1d0406721c3f9a013 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Nov 2015 23:14:30 +0100 +Subject: [PATCH] sd-journal: various clean-ups and modernizations + +- Always print a debug log message about files and directories we cannot + open right when it happens instead of the caller, thus reducing the + number of places where we need to generate the debug message. + +- Always push the errors we encounter immediately into the error set, + when we run into them, instead of in the caller. Thus, we never forget + to push them in. + +- Use stack instead of heap memory where we can. + +- Make remove_file() void, since it cannot fail anyway and always + returned 0. + +- Make local machine check of journal directories explicit in a + function, to make things more readable. + +- Port to all directory listing loops FOREACH_DIRENT_ALL() + +- sd-daemon is library code, hence never log at higher log levels than + LOG_DEBUG. + +(cherry picked from commit d617408ecbe69db69aefddfcb10a6c054ea46ba0) + +Related: #1465759 +--- + src/journal/sd-journal.c | 242 ++++++++++++++++++++++------------------------- + 1 file changed, 111 insertions(+), 131 deletions(-) + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 3749f9e89..9895d9608 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -1171,6 +1171,8 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) { + } + + static bool file_type_wanted(int flags, const char *filename) { ++ assert(filename); ++ + if (!endswith(filename, ".journal") && !endswith(filename, ".journal~")) + return false; + +@@ -1195,7 +1197,7 @@ static bool file_type_wanted(int flags, const char *filename) { + + static int add_any_file(sd_journal *j, const char *path) { + JournalFile *f = NULL; +- int r; ++ int r, k; + + assert(j); + assert(path); +@@ -1204,20 +1206,23 @@ static int add_any_file(sd_journal *j, const char *path) { + return 0; + + if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { +- log_warning("Too many open journal files, not adding %s.", path); +- return set_put_error(j, -ETOOMANYREFS); ++ log_debug("Too many open journal files, not adding %s.", path); ++ r = -ETOOMANYREFS; ++ goto fail; + } + + r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f); +- if (r < 0) +- return r; ++ if (r < 0) { ++ log_debug_errno(r, "Failed to open journal file %s: %m", path); ++ goto fail; ++ } + + /* journal_file_dump(f); */ + + r = ordered_hashmap_put(j->files, f->path, f); + if (r < 0) { + journal_file_close(f); +- return r; ++ goto fail; + } + + log_debug("File %s added.", f->path); +@@ -1227,10 +1232,17 @@ static int add_any_file(sd_journal *j, const char *path) { + j->current_invalidate_counter ++; + + return 0; ++ ++fail: ++ k = set_put_error(j, r); ++ if (k < 0) ++ return k; ++ ++ return r; + } + + static int add_file(sd_journal *j, const char *prefix, const char *filename) { +- char *path = NULL; ++ const char *path; + + assert(j); + assert(prefix); +@@ -1250,24 +1262,20 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { + return add_any_file(j, path); + } + +-static int remove_file(sd_journal *j, const char *prefix, const char *filename) { +- _cleanup_free_ char *path; ++static void remove_file(sd_journal *j, const char *prefix, const char *filename) { ++ const char *path; + JournalFile *f; + + assert(j); + assert(prefix); + assert(filename); + +- path = strjoin(prefix, "/", filename, NULL); +- if (!path) +- return -ENOMEM; +- ++ path = strjoina(prefix, "/", filename); + f = ordered_hashmap_get(j->files, path); + if (!f) +- return 0; ++ return; + + remove_file_real(j, f); +- return 0; + } + + static void remove_file_real(sd_journal *j, JournalFile *f) { +@@ -1296,12 +1304,27 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { + j->current_invalidate_counter ++; + } + ++static int dirname_is_machine_id(const char *fn) { ++ sd_id128_t id, machine; ++ int r; ++ ++ r = sd_id128_get_machine(&machine); ++ if (r < 0) ++ return r; ++ ++ r = sd_id128_from_string(fn, &id); ++ if (r < 0) ++ return r; ++ ++ return sd_id128_equal(id, machine); ++} ++ + static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { + _cleanup_free_ char *path = NULL; +- int r; + _cleanup_closedir_ DIR *d = NULL; +- sd_id128_t id, mid; ++ struct dirent *de = NULL; + Directory *m; ++ int r, k; + + assert(j); + assert(prefix); +@@ -1310,35 +1333,36 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) + log_debug("Considering %s/%s.", prefix, dirname); + + if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && +- (sd_id128_from_string(dirname, &id) < 0 || +- sd_id128_get_machine(&mid) < 0 || +- !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run")))) ++ !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run"))) + return 0; + + path = strjoin(prefix, "/", dirname, NULL); +- if (!path) +- return -ENOMEM; ++ if (!path) { ++ r = -ENOMEM; ++ goto fail; ++ } + + d = opendir(path); + if (!d) { +- log_debug_errno(errno, "Failed to open %s: %m", path); +- if (errno == ENOENT) +- return 0; +- return -errno; ++ r = log_debug_errno(errno, "Failed to open directory %s: %m", path); ++ goto fail; + } + + m = hashmap_get(j->directories_by_path, path); + if (!m) { + m = new0(Directory, 1); +- if (!m) +- return -ENOMEM; ++ if (!m) { ++ r = -ENOMEM; ++ goto fail; ++ } + + m->is_root = false; + m->path = path; + + if (hashmap_put(j->directories_by_path, m->path, m) < 0) { + free(m); +- return -ENOMEM; ++ r = -ENOMEM; ++ goto fail; + } + + path = NULL; /* avoid freeing in cleanup */ +@@ -1360,41 +1384,30 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) + inotify_rm_watch(j->inotify_fd, m->wd); + } + +- for (;;) { +- struct dirent *de; +- +- errno = 0; +- de = readdir(d); +- if (!de && errno != 0) { +- r = -errno; +- log_debug_errno(errno, "Failed to read directory %s: %m", m->path); +- return r; +- } +- if (!de) +- break; ++ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { + + if (dirent_is_file_with_suffix(de, ".journal") || +- dirent_is_file_with_suffix(de, ".journal~")) { +- r = add_file(j, m->path, de->d_name); +- if (r < 0) { +- log_debug_errno(r, "Failed to add file %s/%s: %m", +- m->path, de->d_name); +- r = set_put_error(j, r); +- if (r < 0) +- return r; +- } +- } ++ dirent_is_file_with_suffix(de, ".journal~")) ++ (void) add_file(j, m->path, de->d_name); + } + + check_network(j, dirfd(d)); + + return 0; ++ ++fail: ++ k = set_put_error(j, r); ++ if (k < 0) ++ return k; ++ ++ return r; + } + +-static int add_root_directory(sd_journal *j, const char *p) { ++static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { + _cleanup_closedir_ DIR *d = NULL; ++ struct dirent *de; + Directory *m; +- int r; ++ int r, k; + + assert(j); + assert(p); +@@ -1407,26 +1420,35 @@ static int add_root_directory(sd_journal *j, const char *p) { + p = strjoina(j->prefix, p); + + d = opendir(p); +- if (!d) +- return -errno; ++ if (!d) { ++ if (errno == ENOENT && missing_ok) ++ return 0; ++ ++ r = log_debug_errno(errno, "Failed to open root directory %s: %m", p); ++ goto fail; ++ } + + m = hashmap_get(j->directories_by_path, p); + if (!m) { + m = new0(Directory, 1); +- if (!m) +- return -ENOMEM; ++ if (!m) { ++ r = -ENOMEM; ++ goto fail; ++ } + + m->is_root = true; + m->path = strdup(p); + if (!m->path) { + free(m); +- return -ENOMEM; ++ r = -ENOMEM; ++ goto fail; + } + + if (hashmap_put(j->directories_by_path, m->path, m) < 0) { + free(m->path); + free(m); +- return -ENOMEM; ++ r = -ENOMEM; ++ goto fail; + } + + j->current_invalidate_counter ++; +@@ -1449,42 +1471,27 @@ static int add_root_directory(sd_journal *j, const char *p) { + if (j->no_new_files) + return 0; + +- for (;;) { +- struct dirent *de; ++ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { + sd_id128_t id; + +- errno = 0; +- de = readdir(d); +- if (!de && errno != 0) { +- r = -errno; +- log_debug_errno(errno, "Failed to read directory %s: %m", m->path); +- return r; +- } +- if (!de) +- break; +- + if (dirent_is_file_with_suffix(de, ".journal") || +- dirent_is_file_with_suffix(de, ".journal~")) { +- r = add_file(j, m->path, de->d_name); +- if (r < 0) { +- log_debug_errno(r, "Failed to add file %s/%s: %m", +- m->path, de->d_name); +- r = set_put_error(j, r); +- if (r < 0) +- return r; +- } +- } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) && +- sd_id128_from_string(de->d_name, &id) >= 0) { +- +- r = add_directory(j, m->path, de->d_name); +- if (r < 0) +- log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name); +- } ++ dirent_is_file_with_suffix(de, ".journal~")) ++ (void) add_file(j, m->path, de->d_name); ++ else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) && ++ sd_id128_from_string(de->d_name, &id) >= 0) ++ (void) add_directory(j, m->path, de->d_name); + } + + check_network(j, dirfd(d)); + + return 0; ++ ++fail: ++ k = set_put_error(j, r); ++ if (k < 0) ++ return k; ++ ++ return r; + } + + static void remove_directory(sd_journal *j, Directory *d) { +@@ -1509,8 +1516,8 @@ static void remove_directory(sd_journal *j, Directory *d) { + } + + static int add_search_paths(sd_journal *j) { +- int r; +- const char search_paths[] = ++ ++ static const char search_paths[] = + "/run/log/journal\0" + "/var/log/journal\0"; + const char *p; +@@ -1520,14 +1527,8 @@ static int add_search_paths(sd_journal *j) { + /* We ignore most errors here, since the idea is to only open + * what's actually accessible, and ignore the rest. */ + +- NULSTR_FOREACH(p, search_paths) { +- r = add_root_directory(j, p); +- if (r < 0 && r != -ENOENT) { +- r = set_put_error(j, r); +- if (r < 0) +- return r; +- } +- } ++ NULSTR_FOREACH(p, search_paths) ++ (void) add_root_directory(j, p, true); + + return 0; + } +@@ -1551,17 +1552,14 @@ static int add_current_paths(sd_journal *j) { + if (!dir) + return -ENOMEM; + +- r = add_root_directory(j, dir); +- if (r < 0) { +- set_put_error(j, r); ++ r = add_root_directory(j, dir, true); ++ if (r < 0) + return r; +- } + } + + return 0; + } + +- + static int allocate_inotify(sd_journal *j) { + assert(j); + +@@ -1689,11 +1687,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f + if (!j) + return -ENOMEM; + +- r = add_root_directory(j, path); +- if (r < 0) { +- set_put_error(j, r); ++ r = add_root_directory(j, path, false); ++ if (r < 0) + goto fail; +- } + + *ret = j; + return 0; +@@ -1718,10 +1714,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla + + STRV_FOREACH(path, paths) { + r = add_any_file(j, *path); +- if (r < 0) { +- log_error_errno(r, "Failed to open %s: %m", *path); ++ if (r < 0) + goto fail; +- } + } + + j->no_new_files = true; +@@ -2061,7 +2055,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) { + if (j->no_new_files) + r = add_current_paths(j); + else if (j->path) +- r = add_root_directory(j, j->path); ++ r = add_root_directory(j, j->path, true); + else + r = add_search_paths(j); + if (r < 0) +@@ -2108,7 +2102,6 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { + + static void process_inotify_event(sd_journal *j, struct inotify_event *e) { + Directory *d; +- int r; + + assert(j); + assert(e); +@@ -2124,20 +2117,10 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { + + /* Event for a journal file */ + +- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { +- r = add_file(j, d->path, e->name); +- if (r < 0) { +- log_debug_errno(r, "Failed to add file %s/%s: %m", +- d->path, e->name); +- set_put_error(j, r); +- } +- +- } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) { +- +- r = remove_file(j, d->path, e->name); +- if (r < 0) +- log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name); +- } ++ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) ++ (void) add_file(j, d->path, e->name); ++ else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) ++ remove_file(j, d->path, e->name); + + } else if (!d->is_root && e->len == 0) { + +@@ -2150,11 +2133,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { + + /* Event for root directory */ + +- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { +- r = add_directory(j, d->path, e->name); +- if (r < 0) +- log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name); +- } ++ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) ++ (void) add_directory(j, d->path, e->name); + } + + return; +@@ -2163,7 +2143,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { + if (e->mask & IN_IGNORED) + return; + +- log_warning("Unknown inotify event."); ++ log_debug("Unknown inotify event."); + } + + static int determine_change(sd_journal *j) { diff --git a/SOURCES/0593-journalctl-when-we-fail-to-open-a-journal-file-print.patch b/SOURCES/0593-journalctl-when-we-fail-to-open-a-journal-file-print.patch new file mode 100644 index 0000000..9d9c0f2 --- /dev/null +++ b/SOURCES/0593-journalctl-when-we-fail-to-open-a-journal-file-print.patch @@ -0,0 +1,204 @@ +From 9f7b08ba18ac3d4fd51e70d78d44b60ffb65411f Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 2 Nov 2015 23:37:05 +0100 +Subject: [PATCH] journalctl: when we fail to open a journal file, print why + +When we enumerate journal files and encounter an invalid one, remember +which this, and show it to the user. + +Note the possibly slightly surprising logic here: we store only one path +per error code. This means we show all error kinds but not every actual +error we encounter. This has the benefit of not requiring us to keep a +potentially unbounded list of errors with their sources around, but can +still provide a pretty complete overview on the errors we encountered. + +Fixes #1669. + +(cherry picked from commit 5768d2594940668506bb4cafa078f654cc20dc5a) + +Resolves: #1465759 +--- + src/journal/journal-internal.h | 2 +- + src/journal/journalctl.c | 27 ++++++++++++++++++----- + src/journal/sd-journal.c | 49 ++++++++++++++++++++++++++++++++++-------- + 3 files changed, 63 insertions(+), 15 deletions(-) + +diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h +index 115d7776d..eb23ac28a 100644 +--- a/src/journal/journal-internal.h ++++ b/src/journal/journal-internal.h +@@ -123,7 +123,7 @@ struct sd_journal { + Hashmap *directories_by_path; + Hashmap *directories_by_wd; + +- Set *errors; ++ Hashmap *errors; + }; + + char *journal_make_match_string(sd_journal *j); +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 8c8379732..0be70764e 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -1783,33 +1783,50 @@ static int access_check_var_log_journal(sd_journal *j) { + static int access_check(sd_journal *j) { + Iterator it; + void *code; ++ char *path; + int r = 0; + + assert(j); + +- if (set_isempty(j->errors)) { ++ if (hashmap_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))) { ++ if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) { + (void) access_check_var_log_journal(j); + + 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) { ++ HASHMAP_FOREACH_KEY(path, code, j->errors, it) { + int err; + + err = abs(PTR_TO_INT(code)); + +- if (err == EACCES) ++ switch (err) { ++ case EACCES: + continue; + +- log_warning_errno(err, "An error was encountered while opening journal files, ignoring: %m"); ++ case ENODATA: ++ log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path); ++ break; ++ ++ case EPROTONOSUPPORT: ++ log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path); ++ break; ++ ++ case EBADMSG: ++ log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path); ++ break; ++ ++ default: ++ log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path); ++ break; ++ } + } + + return r; +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 9895d9608..14b65cfed 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -62,19 +62,46 @@ static bool journal_pid_changed(sd_journal *j) { + return j->original_pid != getpid(); + } + +-/* We return an error here only if we didn't manage to +- memorize the real error. */ +-static int set_put_error(sd_journal *j, int r) { ++static int journal_put_error(sd_journal *j, int r, const char *path) { ++ char *copy; + int k; + ++ /* Memorize an error we encountered, and store which ++ * file/directory it was generated from. Note that we store ++ * only *one* path per error code, as the error code is the ++ * key into the hashmap, and the path is the value. This means ++ * we keep track only of all error kinds, but not of all error ++ * locations. This has the benefit that the hashmap cannot ++ * grow beyond bounds. ++ * ++ * We return an error here only if we didn't manage to ++ * memorize the real error. */ ++ + if (r >= 0) + return r; + +- k = set_ensure_allocated(&j->errors, NULL); ++ k = hashmap_ensure_allocated(&j->errors, NULL); + if (k < 0) + return k; + +- return set_put(j->errors, INT_TO_PTR(r)); ++ if (path) { ++ copy = strdup(path); ++ if (!copy) ++ return -ENOMEM; ++ } else ++ copy = NULL; ++ ++ k = hashmap_put(j->errors, INT_TO_PTR(r), copy); ++ if (k < 0) { ++ free(copy); ++ ++ if (k == -EEXIST) ++ return 0; ++ ++ return k; ++ } ++ ++ return 0; + } + + static void detach_location(sd_journal *j) { +@@ -1234,7 +1261,7 @@ static int add_any_file(sd_journal *j, const char *path) { + return 0; + + fail: +- k = set_put_error(j, r); ++ k = journal_put_error(j, r, path); + if (k < 0) + return k; + +@@ -1396,7 +1423,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) + return 0; + + fail: +- k = set_put_error(j, r); ++ k = journal_put_error(j, r, path ?: dirname); + if (k < 0) + return k; + +@@ -1487,7 +1514,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { + return 0; + + fail: +- k = set_put_error(j, r); ++ k = journal_put_error(j, r, p); + if (k < 0) + return k; + +@@ -1732,6 +1759,7 @@ fail: + _public_ void sd_journal_close(sd_journal *j) { + Directory *d; + JournalFile *f; ++ char *p; + + if (!j) + return; +@@ -1759,10 +1787,13 @@ _public_ void sd_journal_close(sd_journal *j) { + mmap_cache_unref(j->mmap); + } + ++ while ((p = hashmap_steal_first(j->errors))) ++ free(p); ++ hashmap_free(j->errors); ++ + free(j->path); + free(j->prefix); + free(j->unique_field); +- set_free(j->errors); + free(j); + } + diff --git a/SOURCES/0594-journald-fix-accuracy-of-watchdog-timer-event.patch b/SOURCES/0594-journald-fix-accuracy-of-watchdog-timer-event.patch new file mode 100644 index 0000000..e80a7e6 --- /dev/null +++ b/SOURCES/0594-journald-fix-accuracy-of-watchdog-timer-event.patch @@ -0,0 +1,31 @@ +From 5386dfa655da623cbd5ab1be6c9c66ad866fc17a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 12 Nov 2015 12:33:10 +0100 +Subject: [PATCH] journald: fix accuracy of watchdog timer event + +Adding 3/4th of the watchdog frequency as accuracy on top of 1/2 of the +watchdog frequency means we might end up at 5/4th of the frequency which +means we might miss the message from time to time. + +Maybe fixes #1804 + +(cherry picked from commit 4de2402b603ea2f518f451d06f09e15aeae54fab) + +Related: #1511565 +--- + src/journal/journald-server.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index 6e7568b60..7c69061f4 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1716,7 +1716,7 @@ static int server_connect_notify(Server *s) { + if (sd_watchdog_enabled(false, &s->watchdog_usec) > 0) { + s->send_watchdog = true; + +- r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec*3/4, dispatch_watchdog, s); ++ r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec/4, dispatch_watchdog, s); + if (r < 0) + return log_error_errno(r, "Failed to add watchdog time event: %m"); + } diff --git a/SOURCES/0595-core-fix-the-reversed-sanity-check-when-setting-Star.patch b/SOURCES/0595-core-fix-the-reversed-sanity-check-when-setting-Star.patch new file mode 100644 index 0000000..498bad3 --- /dev/null +++ b/SOURCES/0595-core-fix-the-reversed-sanity-check-when-setting-Star.patch @@ -0,0 +1,28 @@ +From 468004bfb6efeef42b9191ee218304f0ab492654 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Mon, 23 May 2016 16:48:46 -0400 +Subject: [PATCH] core: fix the reversed sanity check when setting + StartupBlockIOWeight over dbus + +bus_cgroup_set_property() was rejecting if the input value was in range. +Reverse it. + +Cherry-picked from: 6fb09269769634df1096663ce90fac47585eb63a +Resolves: #1302305 +--- + src/core/dbus-cgroup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index ffeeb5aa9..66b1324fe 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -324,7 +324,7 @@ int bus_cgroup_set_property( + if (r < 0) + return r; + +- if (CGROUP_BLKIO_WEIGHT_IS_OK(weight)) ++ if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight)) + return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range"); + + if (mode != UNIT_CHECK) { diff --git a/SOURCES/0596-shared-dropin-ignore-ENAMETOOLONG-when-checking-drop.patch b/SOURCES/0596-shared-dropin-ignore-ENAMETOOLONG-when-checking-drop.patch new file mode 100644 index 0000000..180ee6d --- /dev/null +++ b/SOURCES/0596-shared-dropin-ignore-ENAMETOOLONG-when-checking-drop.patch @@ -0,0 +1,37 @@ +From 3ce9a9b286825793548ed7a7673dd9674a4e4137 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= +Date: Fri, 1 Dec 2017 20:34:49 +0100 +Subject: [PATCH] shared/dropin: ignore ENAMETOOLONG when checking drop-in + directories (#7525) + +This usually happens for device units with long +path in /sys. But users can't even create such drop-ins, +so lets just ignore the error here. + +Fixes #6867 + +Cherry-picked from: dfeec916b57b593ce07d3751aebdb0cce1d05201 +Resolves: #1489095 +--- + src/shared/dropin.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/shared/dropin.c b/src/shared/dropin.c +index d1baad619..b674d307a 100644 +--- a/src/shared/dropin.c ++++ b/src/shared/dropin.c +@@ -129,8 +129,12 @@ static int iterate_dir( + + d = opendir(path); + if (!d) { +- if (errno == ENOENT) +- return 0; ++ /* Ignore ENOENT, after all most units won't have a drop-in dir. ++ * Also ignore ENAMETOOLONG, users are not even able to create ++ * the drop-in dir in such case. This mostly happens for device units with long /sys path. ++ * */ ++ if (IN_SET(errno, ENOENT, ENAMETOOLONG)) ++ return 0; + + log_error_errno(errno, "Failed to open directory %s: %m", path); + return -errno; diff --git a/SOURCES/0597-cryptsetup-when-unlocking-always-put-path-to-the-obj.patch b/SOURCES/0597-cryptsetup-when-unlocking-always-put-path-to-the-obj.patch new file mode 100644 index 0000000..3d5962d --- /dev/null +++ b/SOURCES/0597-cryptsetup-when-unlocking-always-put-path-to-the-obj.patch @@ -0,0 +1,52 @@ +From ec71ee722b573560c14840214adab862b09280c3 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 12 Dec 2017 17:49:14 +0100 +Subject: [PATCH] cryptsetup: when unlocking always put path to the object into + Id + +Some ask-password agents (e.g. clevis-luks-askpass) use Id option from +/run/systemd/ask-password/ask* file in order to obtain the password for +the device. + +Id option should be in the following format, +e.g. Id=subsystem:data. Where data part is supposed to identify object +that ask-password query is done for. Since +e51b9486d1b59e72c293028fed1384f4e4ef09aa this field has format +Id=cryptsetup:/dev/block/major:minor when systemd-cryptsetup is +unlocking encrypted block device. However, crypttab also supports +encrypted image files in which case we usually set data part of Id to +"vol on mountpoint". This is unexpected and actually breaks network +based device encryption as implemented by clevis. + +Example: +$ cat /etc/crypttab +clevis-unlocked /clevis-test-disk-image none luks,_netdev +$ systemctl start 'systemd-cryptsetup@clevis\x2dunlocked.service' +$ grep Id /run/systemd/ask-password/ask* + +Before: +$ Id=cryptsetup:clevis-unlocked on /clevis-test-disk-image-mnt + +After: +$ Id=cryptsetup:/clevis-test-disk-image + +(cherry-picked from commit 5a9f1b05ed6dad48958097fb37811668e69447fb) + +Resolves: #1511043 +--- + src/cryptsetup/cryptsetup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index 5dedb073e..c57d2b294 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -342,7 +342,7 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc + escaped_name = maj_min; + maj_min = NULL; + } else +- escaped_name = cescape(name); ++ escaped_name = cescape(src); + + if (!escaped_name) + return log_oom(); diff --git a/SOURCES/0598-cryptsetup-use-more-descriptive-name-for-the-variabl.patch b/SOURCES/0598-cryptsetup-use-more-descriptive-name-for-the-variabl.patch new file mode 100644 index 0000000..77832cc --- /dev/null +++ b/SOURCES/0598-cryptsetup-use-more-descriptive-name-for-the-variabl.patch @@ -0,0 +1,106 @@ +From 1e02c945fbf54f2b9179ab84794a05cffb3efd98 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 12 Dec 2017 20:00:31 +0100 +Subject: [PATCH] cryptsetup: use more descriptive name for the variable and + drop redundant function + +Let's rename escaped_name to disk_path since this is an actual content +that pointer refers to. It is either path to encrypted block device +or path to encrypted image file. + +Also drop redundant function disk_major_minor(). src is always set, and +it always points to either encrypted block device path (or symlink to +such device) or to encrypted image. In case it is set to device path +there is no need to reset it to /dev/block/major:minor symlink since +those paths are equivalent. + +(cherry-picked from commit ea7e7c1e9c3b579ee94a11a192f1013ee4cb829e) + +Related: #1511043 +--- + src/cryptsetup/cryptsetup.c | 41 ++++++++--------------------------------- + 1 file changed, 8 insertions(+), 33 deletions(-) + +diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c +index c57d2b294..69a015614 100644 +--- a/src/cryptsetup/cryptsetup.c ++++ b/src/cryptsetup/cryptsetup.c +@@ -217,23 +217,6 @@ static void log_glue(int level, const char *msg, void *usrptr) { + log_debug("%s", msg); + } + +-static int disk_major_minor(const char *path, char **ret) { +- struct stat st; +- +- assert(path); +- +- if (stat(path, &st) < 0) +- return -errno; +- +- if (!S_ISBLK(st.st_mode)) +- return -EINVAL; +- +- if (asprintf(ret, "/dev/block/%d:%d", major(st.st_rdev), minor(st.st_rdev)) < 0) +- return -errno; +- +- return 0; +-} +- + static char* disk_description(const char *path) { + + static const char name_fields[] = +@@ -299,11 +282,11 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc + int r = 0; + char **p; + _cleanup_free_ char *text = NULL; +- _cleanup_free_ char *escaped_name = NULL; ++ _cleanup_free_ char *disk_path = NULL; + char *id; + const char *name = NULL; + _cleanup_free_ char *description = NULL, *name_buffer = NULL, +- *mount_point = NULL, *maj_min = NULL; ++ *mount_point = NULL; + + assert(vol); + assert(src); +@@ -312,6 +295,10 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc + description = disk_description(src); + mount_point = disk_mount_point(vol); + ++ disk_path = cescape(src); ++ if (!disk_path) ++ return log_oom(); ++ + if (description && streq(vol, description)) { + /* If the description string is simply the + * volume name, then let's not show this +@@ -335,19 +322,7 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc + if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) + return log_oom(); + +- if (src) +- (void) disk_major_minor(src, &maj_min); +- +- if (maj_min) { +- escaped_name = maj_min; +- maj_min = NULL; +- } else +- escaped_name = cescape(src); +- +- if (!escaped_name) +- return log_oom(); +- +- id = strjoina("cryptsetup:", escaped_name); ++ id = strjoina("cryptsetup:", disk_path); + + r = ask_password_auto(text, "drive-harddisk", id, until, accept_cached, passwords); + if (r < 0) +@@ -361,7 +336,7 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc + if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) + return log_oom(); + +- id = strjoina("cryptsetup-verification:", escaped_name); ++ id = strjoina("cryptsetup-verification:", disk_path); + + r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2); + if (r < 0) diff --git a/SOURCES/0599-cryptsetup-generator-do-not-bind-to-the-decrypted-de.patch b/SOURCES/0599-cryptsetup-generator-do-not-bind-to-the-decrypted-de.patch new file mode 100644 index 0000000..e53a384 --- /dev/null +++ b/SOURCES/0599-cryptsetup-generator-do-not-bind-to-the-decrypted-de.patch @@ -0,0 +1,31 @@ +From 1fa67ac23b3fff0e04c55df8cca6a54994adf175 Mon Sep 17 00:00:00 2001 +From: Ivan Shapovalov +Date: Wed, 30 Aug 2017 19:49:07 +0300 +Subject: [PATCH] cryptsetup-generator: do not bind to the decrypted device + unit (#6538) + +This breaks things when the decrypted device is not immediately +`SYSTEMD_READY=1` (e. g. when a multi-device btrfs system is placed on +multiple cryptsetup devices). + +Fixes #6537. + +(cherry picked from commit e9ea4526a3a3b41eced29b8d742498cc36750424) + +Related: #1511043 +--- + src/cryptsetup/cryptsetup-generator.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c +index c387e2104..5f29093f5 100644 +--- a/src/cryptsetup/cryptsetup-generator.c ++++ b/src/cryptsetup/cryptsetup-generator.c +@@ -110,7 +110,6 @@ static int create_disk( + "SourcePath=/etc/crypttab\n" + "DefaultDependencies=no\n" + "Conflicts=umount.target\n" +- "BindsTo=dev-mapper-%%i.device\n" + "IgnoreOnIsolate=true\n" + "After=systemd-readahead-collect.service systemd-readahead-replay.service\n" + "After=%s\n", diff --git a/SOURCES/0600-shared-cgroup-utils-_CGROUP_CONTROLLER_MASK_ALL-does.patch b/SOURCES/0600-shared-cgroup-utils-_CGROUP_CONTROLLER_MASK_ALL-does.patch new file mode 100644 index 0000000..288ad7b --- /dev/null +++ b/SOURCES/0600-shared-cgroup-utils-_CGROUP_CONTROLLER_MASK_ALL-does.patch @@ -0,0 +1,28 @@ +From 864cf889ecf371df9e67f27682a8f9bc0f68e153 Mon Sep 17 00:00:00 2001 +From: Lukas Nykryn +Date: Tue, 9 Jan 2018 12:59:19 +0100 +Subject: [PATCH] shared/cgroup-utils: _CGROUP_CONTROLLER_MASK_ALL does not + cover CGROUP_PIDS + +7d44d0d43465892d4753ff50592588f49d56cf95 added a CGROUP_PIDS but +did not bump _CGROUP_CONTROLLER_MASK_ALL. + +RHEL-only +Resolves: #1532586 +--- + src/shared/cgroup-util.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h +index 615c1f03e..b6f28c5c2 100644 +--- a/src/shared/cgroup-util.h ++++ b/src/shared/cgroup-util.h +@@ -36,7 +36,7 @@ typedef enum CGroupControllerMask { + CGROUP_MEMORY = 8, + CGROUP_DEVICE = 16, + CGROUP_PIDS = 32, +- _CGROUP_CONTROLLER_MASK_ALL = 31 ++ _CGROUP_CONTROLLER_MASK_ALL = 63 + } CGroupControllerMask; + + /* Special values for the cpu.shares attribute */ diff --git a/SOURCES/0601-automount-ack-automount-requests-even-when-already-m.patch b/SOURCES/0601-automount-ack-automount-requests-even-when-already-m.patch new file mode 100644 index 0000000..d0b9e21 --- /dev/null +++ b/SOURCES/0601-automount-ack-automount-requests-even-when-already-m.patch @@ -0,0 +1,82 @@ +From d9df4d0ed03f56036b04e19a8e6be2c028c4a72e Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 17 Jan 2018 09:13:24 +0100 +Subject: [PATCH] automount: ack automount requests even when already mounted + +If a process accesses an autofs filesystem while systemd is in the +middle of starting the mount unit on top of it, it is possible for the +autofs_ptype_missing_direct request from the kernel to be received after +the mount unit has been fully started: + + systemd forks and execs mount ... + ... access autofs, blocks + mount exits ... + systemd receives SIGCHLD ... + ... kernel sends request + systemd receives request ... + +systemd needs to respond to this request, otherwise the kernel will +continue to block access to the mount point. + +(cherry picked from commit e7d54bf58789545a9eb0b3964233defa0b007318) + +Resolves: #1535135 +--- + src/core/automount.c | 28 ++++++++++++++++------------ + 1 file changed, 16 insertions(+), 12 deletions(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index 20a5de8ca..182ba5240 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -712,7 +712,7 @@ static int automount_start_expire(Automount *a) { + automount_dispatch_expire, a); + } + +-static void automount_enter_runnning(Automount *a) { ++static void automount_enter_running(Automount *a) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + struct stat st; + int r; +@@ -744,18 +744,22 @@ static void automount_enter_runnning(Automount *a) { + goto fail; + } + +- if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) ++ /* The mount unit may have been explicitly started before we got the ++ * autofs request. Ack it to unblock anything waiting on the mount point. */ ++ if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) { + log_unit_info(UNIT(a)->id, + "%s's automount point already active?", UNIT(a)->id); +- else { +- r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), +- JOB_REPLACE, true, &error, NULL); +- if (r < 0) { +- log_unit_warning(UNIT(a)->id, +- "%s failed to queue mount startup job: %s", +- UNIT(a)->id, bus_error_message(&error, r)); +- goto fail; +- } ++ automount_send_ready(a, a->tokens, 0); ++ return; ++ } ++ ++ r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), ++ JOB_REPLACE, true, &error, NULL); ++ if (r < 0) { ++ log_unit_warning(UNIT(a)->id, ++ "%s failed to queue mount startup job: %s", ++ UNIT(a)->id, bus_error_message(&error, r)); ++ goto fail; + } + + r = automount_start_expire(a); +@@ -979,7 +983,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo + goto fail; + } + +- automount_enter_runnning(a); ++ automount_enter_running(a); + break; + + case autofs_ptype_expire_direct: diff --git a/SOURCES/0602-udev-net_id-add-support-for-platform-bus-ACPI-mostly.patch b/SOURCES/0602-udev-net_id-add-support-for-platform-bus-ACPI-mostly.patch new file mode 100644 index 0000000..cbcc4d5 --- /dev/null +++ b/SOURCES/0602-udev-net_id-add-support-for-platform-bus-ACPI-mostly.patch @@ -0,0 +1,134 @@ +From 2a73ec2f11e5dde5754260d0ce99778f35ec92cc Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Wed, 17 Jan 2018 10:08:08 +0100 +Subject: [PATCH] udev: net_id add support for platform bus (ACPI, mostly + arm64) devices + +(cherry picked from commit c20e6de897b2378bc3f936e1e265d2d2e2450a73) + +Note: There is RHEL-only code in the patch. After some discussion, +we only want to rename Hisilicon Network Subsystem (HNS) devices. + +Resolves: #1529633 +--- + src/udev/udev-builtin-net_id.c | 72 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 72 insertions(+) + +diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c +index 19e1f2631..69cee5a72 100644 +--- a/src/udev/udev-builtin-net_id.c ++++ b/src/udev/udev-builtin-net_id.c +@@ -42,6 +42,7 @@ + * -- PCI geographical location + * [P]ps[f][u][..][c][i] + * -- USB port number chain ++ * ai -- Platform bus ACPI instance id + * + * All multi-function PCI devices will carry the [f] number in the + * device name, including the function 0 device. +@@ -100,6 +101,7 @@ + + #include "udev.h" + #include "fileio.h" ++#include "def.h" + + #define ONBOARD_INDEX_MAX (16*1024-1) + +@@ -110,6 +112,7 @@ enum netname_type{ + NET_BCMA, + NET_VIRTIO, + NET_CCWGROUP, ++ NET_PLATFORM, + }; + + struct netnames { +@@ -127,6 +130,7 @@ struct netnames { + char usb_ports[IFNAMSIZ]; + char bcma_core[IFNAMSIZ]; + char ccw_group[IFNAMSIZ]; ++ char platform_path[IFNAMSIZ]; + }; + + /* retrieve on-board index number and label from firmware */ +@@ -288,6 +292,64 @@ out: + return err; + } + ++#define _PLATFORM_TEST "/sys/devices/platform/vvvvPPPP" ++#define _PLATFORM_PATTERN4 "/sys/devices/platform/%4s%4x:%2x/net/eth%u" ++#define _PLATFORM_PATTERN3 "/sys/devices/platform/%3s%4x:%2x/net/eth%u" ++ ++static int names_platform(struct udev_device *dev, struct netnames *names, bool test) { ++ struct udev_device *parent; ++ char vendor[5]; ++ unsigned model, instance, ethid; ++ const char *syspath, *pattern, *validchars; ++ ++ /* check if our direct parent is a platform device with no other bus in-between */ ++ parent = udev_device_get_parent(dev); ++ if (!parent) ++ return -ENOENT; ++ ++ if (!streq_ptr("platform", udev_device_get_subsystem(parent))) ++ return -ENOENT; ++ ++ syspath = udev_device_get_syspath(dev); ++ ++ /* syspath is too short, to have a valid ACPI instance */ ++ if (strlen(syspath) < sizeof _PLATFORM_TEST) ++ return -EINVAL; ++ ++ /* Vendor ID can be either PNP ID (3 chars A-Z) or ACPI ID (4 chars A-Z and numerals) */ ++ if (syspath[sizeof _PLATFORM_TEST - 1] == ':') { ++ pattern = _PLATFORM_PATTERN4; ++ validchars = UPPERCASE_LETTERS DIGITS; ++ } else { ++ pattern = _PLATFORM_PATTERN3; ++ validchars = UPPERCASE_LETTERS; ++ } ++ ++ /* RHEL-only! */ ++ /* We only want to rename HNS cards */ ++ if (!startswith(syspath, "/sys/devices/platform/HISI")) ++ return -ENOENT; ++ ++ /* Platform devices are named after ACPI table match, and instance id ++ * eg. "/sys/devices/platform/HISI00C2:00"); ++ * The Vendor (3 or 4 char), followed by hexdecimal model number : instance id. ++ */ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wformat-nonliteral" ++ if (sscanf(syspath, pattern, vendor, &model, &instance, ðid) != 4) ++ return -EINVAL; ++#pragma GCC diagnostic pop ++ ++ if (!in_charset(vendor, validchars)) ++ return -ENOENT; ++ ++ ascii_strlower(vendor); ++ ++ xsprintf(names->platform_path, "a%s%xi%u", vendor, model, instance); ++ names->type = NET_PLATFORM; ++ return 0; ++} ++ + static int names_pci(struct udev_device *dev, struct netnames *names) { + struct udev_device *parent; + static int do_virtio = -1; +@@ -555,6 +617,16 @@ static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool + goto out; + } + ++ /* get ACPI path names for ARM64 platform devices */ ++ err = names_platform(dev, &names, test); ++ if (err >= 0 && names.type == NET_PLATFORM) { ++ char str[IFNAMSIZ]; ++ ++ if (snprintf(str, sizeof(str), "%s%s", prefix, names.platform_path) < (int)sizeof(str)) ++ udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str); ++ goto out; ++ } ++ + /* get PCI based path names, we compose only PCI based paths */ + err = names_pci(dev, &names); + if (err < 0) diff --git a/SOURCES/0603-journald-native-Fix-typo-in-MANDLOCK-message.patch b/SOURCES/0603-journald-native-Fix-typo-in-MANDLOCK-message.patch new file mode 100644 index 0000000..1e36686 --- /dev/null +++ b/SOURCES/0603-journald-native-Fix-typo-in-MANDLOCK-message.patch @@ -0,0 +1,24 @@ +From fd5cce8255e14fd619654d3d639485787afdc89c Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Mon, 22 Jan 2018 11:18:53 +0100 +Subject: [PATCH] journald-native: Fix typo in MANDLOCK message + +Cherry-picked from: 1dc52f56f9641be12470be664d16043a7a08ff37 +Resolves: #1501017 +--- + src/journal/journald-native.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c +index fdb1a38dd..cf3349393 100644 +--- a/src/journal/journald-native.c ++++ b/src/journal/journald-native.c +@@ -406,7 +406,7 @@ void server_process_native_file( + * https://github.com/systemd/systemd/issues/1822 + */ + if (vfs.f_flag & ST_MANDLOCK) { +- log_error("Received file descriptor from file system with mandatory locking enable, refusing."); ++ log_error("Received file descriptor from file system with mandatory locking enabled, refusing."); + return; + } + diff --git a/SOURCES/0604-process-util-make-our-freeze-routine-do-something-us.patch b/SOURCES/0604-process-util-make-our-freeze-routine-do-something-us.patch new file mode 100644 index 0000000..4507872 --- /dev/null +++ b/SOURCES/0604-process-util-make-our-freeze-routine-do-something-us.patch @@ -0,0 +1,45 @@ +From 04213418a4e8d4e7f74f5b8b03713172a658d9e4 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 12 Jan 2018 13:05:48 +0100 +Subject: [PATCH] process-util: make our freeze() routine do something useful + +When we crash we freeze() our-self (or possibly we reboot the machine if +that is configured). However, calling pause() is very unhelpful thing to +do. We should at least continue to do what init systems being doing +since 70's and that is reaping zombies. Otherwise zombies start to +accumulate on the system which is a very bad thing. As that can prevent +admin from taking manual steps to reboot the machine in somewhat +graceful manner (e.g. manually stopping services, unmounting data +volumes and calling reboot -f). + +Fixes #7783 + +(cherry picked from commit 8647283e453e4039029e2b21270241fa4010b3d8) + +Resolves: #1540941 +--- + src/shared/util.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/shared/util.c b/src/shared/util.c +index 39359fcc8..af0953273 100644 +--- a/src/shared/util.c ++++ b/src/shared/util.c +@@ -4158,6 +4158,17 @@ noreturn void freeze(void) { + + sync(); + ++ /* Let's not freeze right away, but keep reaping zombies. */ ++ for (;;) { ++ int r; ++ siginfo_t si = {}; ++ ++ r = waitid(P_ALL, 0, &si, WEXITED); ++ if (r < 0 && errno != EINTR) ++ break; ++ } ++ ++ /* waitid() failed with an unexpected error, things are really borked. Freeze now! */ + for (;;) + pause(); + } diff --git a/SOURCES/0605-dbus-propagate-errors-from-bus_init_system-and-bus_i.patch b/SOURCES/0605-dbus-propagate-errors-from-bus_init_system-and-bus_i.patch new file mode 100644 index 0000000..bc131c8 --- /dev/null +++ b/SOURCES/0605-dbus-propagate-errors-from-bus_init_system-and-bus_i.patch @@ -0,0 +1,131 @@ +From ac8fd4f713c1861e8a62fd811b2e79acbee5db31 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Wed, 10 Jan 2018 17:22:12 +0100 +Subject: [PATCH] dbus: propagate errors from bus_init_system() and + bus_init_api() + +The aim of this change is to make sure that we properly log about all +D-Bus connection problems. After all, we only ever attempt to get on the +bus if dbus-daemon is around, so any failure in the process should be +treated as an error. + +bus_init_system() is only called from bus_init() and in +bus_init() we have a bool flag which governs whether we should attempt +to connect to the system bus or not. +Hence if we are in bus_init_system() then it is clear we got called from +a context where connection to the bus is actually required and therefore +shouldn't be treated as the "best effort" type of operation. Same +applies to bus_init_api(). + +We make use of those error codes in bus_init() and log high level +message that informs admin about what is going on (and is easy to spot +and makes sense to an end user). + +Also "retrying later" bit is actually a lie. We won't retry unless we +are explicitly told to reconnect via SIGUSR1 or re-executed. This is +because bus_init() is always called from the context where dbus-daemon +is already around and hence bus_init() won't be called again from +unit_notify(). + +Fixes #7782 + +(cherry picked from commit dc7118ba094415d8de3812881cc5cbe2e3cac73e) + +Resolves: #1541061 +--- + src/core/dbus.c | 46 +++++++++++++++++----------------------------- + 1 file changed, 17 insertions(+), 29 deletions(-) + +diff --git a/src/core/dbus.c b/src/core/dbus.c +index 0061211fa..d551eab01 100644 +--- a/src/core/dbus.c ++++ b/src/core/dbus.c +@@ -811,27 +811,21 @@ static int bus_init_api(Manager *m) { + else + r = sd_bus_open_user(&bus); + +- if (r < 0) { +- log_debug("Failed to connect to API bus, retrying later..."); +- return 0; +- } ++ if (r < 0) ++ return log_error_errno(r, "Failed to connect to API bus: %m"); + + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); +- if (r < 0) { +- log_error_errno(r, "Failed to attach API bus to event loop: %m"); +- return 0; +- } ++ if (r < 0) ++ return log_error_errno(r, "Failed to attach API bus to event loop: %m"); + + r = bus_setup_disconnected_match(m, bus); + if (r < 0) +- return 0; ++ return r; + } + + r = bus_setup_api(m, bus); +- if (r < 0) { +- log_error_errno(r, "Failed to set up API bus: %m"); +- return 0; +- } ++ if (r < 0) ++ return log_error_errno(r, "Failed to set up API bus: %m"); + + m->api_bus = bus; + bus = NULL; +@@ -880,26 +874,20 @@ static int bus_init_system(Manager *m) { + } + + r = sd_bus_open_system(&bus); +- if (r < 0) { +- log_debug("Failed to connect to system bus, retrying later..."); +- return 0; +- } ++ if (r < 0) ++ return log_error_errno(r, "Failed to connect to system bus: %m"); + + r = bus_setup_disconnected_match(m, bus); + if (r < 0) +- return 0; ++ return r; + + r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL); +- if (r < 0) { +- log_error_errno(r, "Failed to attach system bus to event loop: %m"); +- return 0; +- } ++ if (r < 0) ++ return log_error_errno(r, "Failed to attach system bus to event loop: %m"); + + r = bus_setup_system(m, bus); +- if (r < 0) { +- log_error_errno(r, "Failed to set up system bus: %m"); +- return 0; +- } ++ if (r < 0) ++ return log_error_errno(r, "Failed to set up system bus: %m"); + + m->system_bus = bus; + bus = NULL; +@@ -984,16 +972,16 @@ int bus_init(Manager *m, bool try_bus_connect) { + if (try_bus_connect) { + r = bus_init_system(m); + if (r < 0) +- return r; ++ return log_error_errno(r, "Failed to initialize D-Bus connection: %m"); + + r = bus_init_api(m); + if (r < 0) +- return r; ++ return log_error_errno(r, "Error occured during D-Bus APIs initialization: %m"); + } + + r = bus_init_private(m); + if (r < 0) +- return r; ++ return log_error_errno(r, "Failed to create private D-Bus server: %m"); + + return 0; + } diff --git a/SOURCES/0606-bus-util.c-fix-TasksMax-property-assignment.patch b/SOURCES/0606-bus-util.c-fix-TasksMax-property-assignment.patch new file mode 100644 index 0000000..2630ceb --- /dev/null +++ b/SOURCES/0606-bus-util.c-fix-TasksMax-property-assignment.patch @@ -0,0 +1,44 @@ +From fc0a9c4e9701370822014298849116da2d3e41f3 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 30 Jan 2018 12:58:42 +0100 +Subject: [PATCH] bus-util.c: fix TasksMax= property assignment + +Also, with the current code structure, it's not possible to also set +the TasksMaxScale= in the same if branch, simply because how the +sd_bus_message_append() is used. In src/systemctl/systemctl.c, the +message container is already open in set_property(). + +Resolves: #1537147 +--- + src/libsystemd/sd-bus/bus-util.c | 15 ++++----------- + 1 file changed, 4 insertions(+), 11 deletions(-) + +diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c +index cbf1eccf7..b1bdbad2d 100644 +--- a/src/libsystemd/sd-bus/bus-util.c ++++ b/src/libsystemd/sd-bus/bus-util.c +@@ -1418,20 +1418,13 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen + if (isempty(eq) || streq(eq, "infinity")) + t = (uint64_t) -1; + else { +- r = parse_percent(eq); +- if (r >= 0) { +- r = sd_bus_message_append(m, "sv", "TasksMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); +- if (r < 0) +- return bus_log_create_error(r); +- } else { +- r = safe_atou64(eq, &t); +- if (r < 0) +- return log_error_errno(r, "Failed to parse maximum tasks specification %s", assignment); +- } ++ r = safe_atou64(eq, &t); ++ if (r < 0) ++ return log_error_errno(r, "Failed to parse maximum tasks specification %s", assignment); + + } + +- r = sd_bus_message_append(m, "sv", "TasksMax", "t", t); ++ r = sd_bus_message_append(m, "v", "t", t); + + } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) { + uint64_t u; diff --git a/SOURCES/0607-sparse-avoid-clash-with-__bitwise-and-__force-from-4.patch b/SOURCES/0607-sparse-avoid-clash-with-__bitwise-and-__force-from-4.patch new file mode 100644 index 0000000..1283fd0 --- /dev/null +++ b/SOURCES/0607-sparse-avoid-clash-with-__bitwise-and-__force-from-4.patch @@ -0,0 +1,89 @@ +From 59a855f7dbbd79c01ab9e8d326e986de786dda3f Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Wed, 11 Jan 2017 10:50:25 +0100 +Subject: [PATCH] sparse: avoid clash with __bitwise and __force from 4.10 + linux/types.h (#5061) + +It also used __bitwise and __force. It seems easier to rename +our versions since they are local to this one single header. + +Also, undefine them afteerwards, so that we don't pollute the +preprocessor macro namespace. + +(cherry picked from commit dc66f33a16596c2886a24da12e56ec096214e124) + +Related: #1447937 +--- + src/shared/sparse-endian.h | 47 ++++++++++++++++++++++++---------------------- + 1 file changed, 25 insertions(+), 22 deletions(-) + +diff --git a/src/shared/sparse-endian.h b/src/shared/sparse-endian.h +index c913fda8c..a3573b84a 100644 +--- a/src/shared/sparse-endian.h ++++ b/src/shared/sparse-endian.h +@@ -26,19 +26,19 @@ + #include + + #ifdef __CHECKER__ +-#define __bitwise __attribute__((bitwise)) +-#define __force __attribute__((force)) ++#define __sd_bitwise __attribute__((bitwise)) ++#define __sd_force __attribute__((force)) + #else +-#define __bitwise +-#define __force ++#define __sd_bitwise ++#define __sd_force + #endif + +-typedef uint16_t __bitwise le16_t; +-typedef uint16_t __bitwise be16_t; +-typedef uint32_t __bitwise le32_t; +-typedef uint32_t __bitwise be32_t; +-typedef uint64_t __bitwise le64_t; +-typedef uint64_t __bitwise be64_t; ++typedef uint16_t __sd_bitwise le16_t; ++typedef uint16_t __sd_bitwise be16_t; ++typedef uint32_t __sd_bitwise le32_t; ++typedef uint32_t __sd_bitwise be32_t; ++typedef uint64_t __sd_bitwise le64_t; ++typedef uint64_t __sd_bitwise be64_t; + + #undef htobe16 + #undef htole16 +@@ -69,20 +69,23 @@ typedef uint64_t __bitwise be64_t; + #define bswap_64_on_be(x) __bswap_64(x) + #endif + +-static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } +-static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } +-static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } ++static inline le16_t htole16(uint16_t value) { return (le16_t __sd_force) bswap_16_on_be(value); } ++static inline le32_t htole32(uint32_t value) { return (le32_t __sd_force) bswap_32_on_be(value); } ++static inline le64_t htole64(uint64_t value) { return (le64_t __sd_force) bswap_64_on_be(value); } + +-static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } +-static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } +-static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } ++static inline be16_t htobe16(uint16_t value) { return (be16_t __sd_force) bswap_16_on_le(value); } ++static inline be32_t htobe32(uint32_t value) { return (be32_t __sd_force) bswap_32_on_le(value); } ++static inline be64_t htobe64(uint64_t value) { return (be64_t __sd_force) bswap_64_on_le(value); } + +-static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } +-static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } +-static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } ++static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __sd_force)value); } ++static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __sd_force)value); } ++static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __sd_force)value); } + +-static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } +-static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } +-static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } ++static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __sd_force)value); } ++static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __sd_force)value); } ++static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __sd_force)value); } ++ ++#undef __sd_bitwise ++#undef __sd_force + + #endif /* SPARSE_ENDIAN_H */ diff --git a/SOURCES/0608-core-Let-two-more-booleans-survive-a-daemon-reload.patch b/SOURCES/0608-core-Let-two-more-booleans-survive-a-daemon-reload.patch new file mode 100644 index 0000000..67a3ed9 --- /dev/null +++ b/SOURCES/0608-core-Let-two-more-booleans-survive-a-daemon-reload.patch @@ -0,0 +1,76 @@ +From ab0cdf76c184cbe7f8376e0a2c8d7a60d10ca9b3 Mon Sep 17 00:00:00 2001 +From: Werner Fink +Date: Wed, 10 Jun 2015 14:36:50 +0200 +Subject: [PATCH] core: Let two more booleans survive a daemon-reload + +Without the boolean bus_name_good services as well as cgroup_realized +for units a unit of Type=dbus and ExecReload sending SIGHUP to $MAINPID +will be terminated if systemd will be daemon reloaded. + +https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=746151 +https://bugs.freedesktop.org/show_bug.cgi?id=78311 +https://bugzilla.opensuse.org/show_bug.cgi?id=934077 + +Cherry-picked from: de1d4f9b5c6345f63edd46f643485eca909995bf +Resolves: #1542391 +--- + src/core/service.c | 9 +++++++++ + src/core/unit.c | 11 +++++++++++ + 2 files changed, 20 insertions(+) + +diff --git a/src/core/service.c b/src/core/service.c +index ceed1cc2e..71ec5e37c 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -2044,6 +2044,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { + unit_serialize_item_format(u, f, "main-pid", PID_FMT, s->main_pid); + + unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known)); ++ unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good)); + + if (s->status_text) + unit_serialize_item(u, f, "status-text", s->status_text); +@@ -2264,6 +2265,14 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, + log_unit_debug(u->id, "Failed to parse main-pid-known value %s", value); + else + s->main_pid_known = b; ++ } else if (streq(key, "bus-name-good")) { ++ int b; ++ ++ b = parse_boolean(value); ++ if (b < 0) ++ log_unit_debug(u->id, "Failed to parse bus-name-good value: %s", value); ++ else ++ s->bus_name_good = b; + } else if (streq(key, "status-text")) { + char *t; + +diff --git a/src/core/unit.c b/src/core/unit.c +index 8c0fde878..41d7b63d7 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2619,6 +2619,7 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { + + if (u->cgroup_path) + unit_serialize_item(u, f, "cgroup", u->cgroup_path); ++ unit_serialize_item(u, f, "cgroup-realized", yes_no(u->cgroup_realized)); + + if (serialize_jobs) { + if (u->job) { +@@ -2809,6 +2810,16 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + u->cgroup_path = s; + assert(hashmap_put(u->manager->cgroup_unit, s, u) == 1); + ++ continue; ++ } else if (streq(l, "cgroup-realized")) { ++ int b; ++ ++ b = parse_boolean(v); ++ if (b < 0) ++ log_unit_debug(u->id, "Failed to parse cgroup-realized bool %s, ignoring.", v); ++ else ++ u->cgroup_realized = b; ++ + continue; + } + diff --git a/SOURCES/0609-core-don-t-choke-if-a-unit-another-unit-triggers-van.patch b/SOURCES/0609-core-don-t-choke-if-a-unit-another-unit-triggers-van.patch new file mode 100644 index 0000000..3a6a0a8 --- /dev/null +++ b/SOURCES/0609-core-don-t-choke-if-a-unit-another-unit-triggers-van.patch @@ -0,0 +1,212 @@ +From d7b2f6efd02375af4cf043ef9db6d316b65d4779 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Fri, 16 Feb 2018 09:56:50 +0100 +Subject: [PATCH] core: don't choke if a unit another unit triggers vanishes + during reload + +Fixes: #1981 + +(cherry picked from e903182e5b0daa941de47a9c08c824106cec7fe0) +Resolves: #1545676 +--- + src/core/automount.c | 25 +++++++++++++++++++++---- + src/core/path.c | 18 +++++++++++++++--- + src/core/timer.c | 30 ++++++++++++++++++++++++++---- + 3 files changed, 62 insertions(+), 11 deletions(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index 182ba5240..679fe071e 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -715,6 +715,7 @@ static int automount_start_expire(Automount *a) { + static void automount_enter_running(Automount *a) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + struct stat st; ++ Unit *trigger; + int r; + + assert(a); +@@ -753,8 +754,13 @@ static void automount_enter_running(Automount *a) { + return; + } + +- r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), +- JOB_REPLACE, true, &error, NULL); ++ trigger = UNIT_TRIGGER(UNIT(a)); ++ if (!trigger) { ++ log_unit_error(UNIT(a)->id, "Unit to trigger vanished."); ++ goto fail; ++ } ++ ++ r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, true, &error, NULL); + if (r < 0) { + log_unit_warning(UNIT(a)->id, + "%s failed to queue mount startup job: %s", +@@ -775,6 +781,7 @@ fail: + + static int automount_start(Unit *u) { + Automount *a = AUTOMOUNT(u); ++ Unit *trigger; + + assert(a); + assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED); +@@ -786,8 +793,11 @@ static int automount_start(Unit *u) { + return -EEXIST; + } + +- if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) ++ trigger = UNIT_TRIGGER(u); ++ if (!trigger || trigger->load_state != UNIT_LOADED) { ++ log_unit_error(u->id, "Refusing to start, unit to trigger not loaded."); + return -ENOENT; ++ } + + a->result = AUTOMOUNT_SUCCESS; + automount_enter_waiting(a); +@@ -936,6 +946,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + union autofs_v5_packet_union packet; + Automount *a = AUTOMOUNT(userdata); ++ Unit *trigger; + ssize_t l; + int r; + +@@ -1002,7 +1013,13 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo + log_unit_error_errno(UNIT(a)->id, r, "Failed to remember token: %m"); + goto fail; + } +- r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL); ++ ++ trigger = UNIT_TRIGGER(UNIT(a)); ++ if (!trigger) { ++ log_unit_error(UNIT(a)->id, "Unit to trigger vanished."); ++ goto fail; ++ } ++ r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, true, &error, NULL); + if (r < 0) { + log_unit_warning(UNIT(a)->id, + "%s failed to queue umount startup job: %s", +diff --git a/src/core/path.c b/src/core/path.c +index 51e36fa8b..0533bb4e2 100644 +--- a/src/core/path.c ++++ b/src/core/path.c +@@ -475,6 +475,7 @@ static void path_enter_dead(Path *p, PathResult f) { + + static void path_enter_running(Path *p) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; ++ Unit *trigger; + int r; + + assert(p); +@@ -483,8 +484,14 @@ static void path_enter_running(Path *p) { + if (unit_stop_pending(UNIT(p))) + return; + +- r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)), +- JOB_REPLACE, true, &error, NULL); ++ trigger = UNIT_TRIGGER(UNIT(p)); ++ if (!trigger) { ++ log_unit_error(UNIT(p)->id, "Unit to trigger vanished."); ++ path_enter_dead(p, TIMER_FAILURE_RESOURCES); ++ return; ++ } ++ ++ r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto fail; + +@@ -566,12 +573,17 @@ static void path_mkdir(Path *p) { + + static int path_start(Unit *u) { + Path *p = PATH(u); ++ Unit *trigger; + + assert(p); + assert(p->state == PATH_DEAD || p->state == PATH_FAILED); + +- if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) ++ ++ trigger = UNIT_TRIGGER(u); ++ if (!trigger || trigger->load_state != UNIT_LOADED) { ++ log_unit_error(u->id, "Refusing to start, unit to trigger not loaded."); + return -ENOENT; ++ } + + path_mkdir(p); + +diff --git a/src/core/timer.c b/src/core/timer.c +index f318dc6f4..91d8db67e 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -343,8 +343,18 @@ static void timer_enter_waiting(Timer *t, bool initial) { + usec_t ts_realtime, ts_monotonic; + usec_t base = 0; + TimerValue *v; ++ Unit *trigger; + int r; + ++ assert(t); ++ ++ trigger = UNIT_TRIGGER(UNIT(t)); ++ if (!trigger) { ++ log_unit_error(UNIT(t)->id, "Unit to trigger vanished."); ++ timer_enter_dead(t, TIMER_FAILURE_RESOURCES); ++ return; ++ } ++ + /* If we shall wake the system we use the boottime clock + * rather than the monotonic clock. */ + +@@ -399,7 +409,7 @@ static void timer_enter_waiting(Timer *t, bool initial) { + + case TIMER_UNIT_ACTIVE: + +- base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic; ++ base = trigger->inactive_exit_timestamp.monotonic; + + if (base <= 0) + base = t->last_trigger.monotonic; +@@ -523,6 +533,7 @@ fail: + + static void timer_enter_running(Timer *t) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; ++ Unit *trigger; + int r; + + assert(t); +@@ -531,8 +542,15 @@ static void timer_enter_running(Timer *t) { + if (unit_stop_pending(UNIT(t))) + return; + +- r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)), +- JOB_REPLACE, true, &error, NULL); ++ ++ trigger = UNIT_TRIGGER(UNIT(t)); ++ if (!trigger) { ++ log_unit_error(UNIT(t)->id, "Unit to trigger vanished."); ++ timer_enter_dead(t, TIMER_FAILURE_RESOURCES); ++ return; ++ } ++ ++ r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, true, &error, NULL); + if (r < 0) + goto fail; + +@@ -554,12 +572,16 @@ fail: + static int timer_start(Unit *u) { + Timer *t = TIMER(u); + TimerValue *v; ++ Unit *trigger; + + assert(t); + assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED); + +- if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) ++ trigger = UNIT_TRIGGER(u); ++ if (!trigger || trigger->load_state != UNIT_LOADED) { ++ log_unit_error(u->id, "Refusing to start, unit to trigger not loaded."); + return -ENOENT; ++ } + + t->last_trigger = DUAL_TIMESTAMP_NULL; + diff --git a/SOURCES/0610-sd-journal-properly-handle-inotify-queue-overflow.patch b/SOURCES/0610-sd-journal-properly-handle-inotify-queue-overflow.patch new file mode 100644 index 0000000..c3f7d24 --- /dev/null +++ b/SOURCES/0610-sd-journal-properly-handle-inotify-queue-overflow.patch @@ -0,0 +1,442 @@ +From 7204e7f9ea3067bda7e5658a06e91b67c736f8ab Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 12 Feb 2018 16:14:58 +0100 +Subject: [PATCH] sd-journal: properly handle inotify queue overflow + +This adds proper handling of IN_Q_OVERFLOW: when the inotify queue runs +over we'll reiterate all directories we are looking at. At the same time +we'll mark all files and directories we encounter that way with a +generation counter we first increased. All files and directories not +marked like this are then unloaded. + +With this logic we do the best when the inotify queue overflows: we +synchronize our in-memory state again with what's on disk. This +contains some refactoring of the directory logic, to share more code +between uuid directories and "root" directories and generally make +things a bit more readable by splitting things up into smaller bits. + +See: #7998 #8032 + +(cherry-picked from commit 858749f7312bd0adb5433075a92e1c35a2fb56ac) + +Resolves: #1540538 +--- + src/journal/journal-file.h | 2 + + src/journal/journal-internal.h | 2 + + src/journal/sd-journal.c | 237 ++++++++++++++++++++++++++++++++--------- + src/shared/path-util.c | 14 +++ + src/shared/path-util.h | 2 + + 5 files changed, 206 insertions(+), 51 deletions(-) + +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index c74ad5fc5..dd8ef52d2 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -121,6 +121,8 @@ typedef struct JournalFile { + + void *fsprg_seed; + size_t fsprg_seed_size; ++ ++ unsigned last_seen_generation; + #endif + } JournalFile; + +diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h +index eb23ac28a..999e9d8cb 100644 +--- a/src/journal/journal-internal.h ++++ b/src/journal/journal-internal.h +@@ -81,6 +81,7 @@ struct Directory { + char *path; + int wd; + bool is_root; ++ unsigned last_seen_generation; + }; + + struct sd_journal { +@@ -102,6 +103,7 @@ struct sd_journal { + int inotify_fd; + unsigned current_invalidate_counter, last_invalidate_counter; + usec_t last_process_usec; ++ unsigned generation; + + char *unique_field; + JournalFile *unique_file; +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 14b65cfed..9186f5188 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -1229,8 +1229,16 @@ static int add_any_file(sd_journal *j, const char *path) { + assert(j); + assert(path); + +- if (ordered_hashmap_get(j->files, path)) +- return 0; ++ if (path) { ++ f = ordered_hashmap_get(j->files, path); ++ if (f) { ++ /* Mark this file as seen in this generation. This is used to GC old files in ++ * process_q_overflow() to detect journal files that are still and discern them from those who ++ * are gone. */ ++ f->last_seen_generation = j->generation; ++ return 0; ++ } ++ } + + if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { + log_debug("Too many open journal files, not adding %s.", path); +@@ -1252,6 +1260,8 @@ static int add_any_file(sd_journal *j, const char *path) { + goto fail; + } + ++ f->last_seen_generation = j->generation; ++ + log_debug("File %s added.", f->path); + + check_network(j, f->fd); +@@ -1346,10 +1356,96 @@ static int dirname_is_machine_id(const char *fn) { + return sd_id128_equal(id, machine); + } + ++static bool dirent_is_journal_file(const struct dirent *de) { ++ assert(de); ++ ++ if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN)) ++ return false; ++ ++ return endswith(de->d_name, ".journal") || ++ endswith(de->d_name, ".journal~"); ++} ++ ++static bool dirent_is_id128_subdir(const struct dirent *de) { ++ assert(de); ++ ++ if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN)) ++ return false; ++ ++ return id128_is_valid(de->d_name); ++} ++ ++static int directory_open(sd_journal *j, const char *path, DIR **ret) { ++ DIR *d; ++ ++ assert(j); ++ assert(path); ++ assert(ret); ++ ++ d = opendir(path); ++ if (!d) ++ return -errno; ++ ++ *ret = d; ++ return 0; ++} ++ ++static int add_directory(sd_journal *j, const char *prefix, const char *dirname); ++ ++static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) { ++ struct dirent *de; ++ ++ assert(j); ++ assert(m); ++ assert(d); ++ ++ FOREACH_DIRENT_ALL(de, d, goto fail) { ++ if (dirent_is_journal_file(de)) ++ (void) add_file(j, m->path, de->d_name); ++ ++ if (m->is_root && dirent_is_id128_subdir(de)) ++ (void) add_directory(j, m->path, de->d_name); ++ } ++ ++ return; ++ ++fail: ++ log_debug_errno(errno, "Failed to enumerate directory %s, ignoring: %m", m->path); ++} ++ ++static void directory_watch(sd_journal *j, Directory *m, int fd, uint32_t mask) { ++ int r; ++ ++ assert(j); ++ assert(m); ++ assert(fd >= 0); ++ ++ /* Watch this directory if that's enabled and if it not being watched yet. */ ++ ++ if (m->wd > 0) /* Already have a watch? */ ++ return; ++ if (j->inotify_fd < 0) /* Not watching at all? */ ++ return; ++ ++ m->wd = inotify_add_watch_fd(j->inotify_fd, fd, mask); ++ if (m->wd < 0) { ++ log_debug_errno(errno, "Failed to watch journal directory '%s', ignoring: %m", m->path); ++ return; ++ } ++ ++ r = hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m); ++ if (r == -EEXIST) ++ log_debug_errno(r, "Directory '%s' already being watched under a different path, ignoring: %m", m->path); ++ if (r < 0) { ++ log_debug_errno(r, "Failed to add watch for journal directory '%s' to hashmap, ignoring: %m", m->path); ++ (void) inotify_rm_watch(j->inotify_fd, m->wd); ++ m->wd = -1; ++ } ++} ++ + static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { + _cleanup_free_ char *path = NULL; + _cleanup_closedir_ DIR *d = NULL; +- struct dirent *de = NULL; + Directory *m; + int r, k; + +@@ -1357,7 +1453,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) + assert(prefix); + assert(dirname); + +- log_debug("Considering %s/%s.", prefix, dirname); ++ log_debug("Considering '%s/%s'.", prefix, dirname); + + if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && + !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run"))) +@@ -1369,9 +1465,9 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) + goto fail; + } + +- d = opendir(path); +- if (!d) { +- r = log_debug_errno(errno, "Failed to open directory %s: %m", path); ++ r = directory_open(j, path, &d); ++ if (r < 0) { ++ r = log_debug_errno(errno, "Failed to open directory '%s': %m", path); + goto fail; + } + +@@ -1398,25 +1494,17 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) + log_debug("Directory %s added.", m->path); + + } else if (m->is_root) +- return 0; +- +- if (m->wd <= 0 && j->inotify_fd >= 0) { +- +- m->wd = inotify_add_watch(j->inotify_fd, m->path, +- IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| +- IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM| +- IN_ONLYDIR); ++ return 0; /* Don't 'downgrade' from root directory */ + +- if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0) +- inotify_rm_watch(j->inotify_fd, m->wd); +- } ++ m->last_seen_generation = j->generation; + +- FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { ++ directory_watch(j, m, dirfd(d), ++ IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| ++ IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM| ++ IN_ONLYDIR); + +- if (dirent_is_file_with_suffix(de, ".journal") || +- dirent_is_file_with_suffix(de, ".journal~")) +- (void) add_file(j, m->path, de->d_name); +- } ++ if (!j->no_new_files) ++ directory_enumerate(j, m, d); + + check_network(j, dirfd(d)); + +@@ -1432,13 +1520,14 @@ fail: + + static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { + _cleanup_closedir_ DIR *d = NULL; +- struct dirent *de; + Directory *m; + int r, k; + + assert(j); + assert(p); + ++ log_debug("Considering root directory '%s'.", p); ++ + if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) && + !path_startswith(p, "/run")) + return -EINVAL; +@@ -1446,12 +1535,11 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { + if (j->prefix) + p = strjoina(j->prefix, p); + +- d = opendir(p); +- if (!d) { +- if (errno == ENOENT && missing_ok) +- return 0; +- +- r = log_debug_errno(errno, "Failed to open root directory %s: %m", p); ++ r = directory_open(j, p, &d); ++ if (r == -ENOENT && missing_ok) ++ return 0; ++ if (r < 0) { ++ log_debug_errno(r, "Failed to open root directory %s: %m", p); + goto fail; + } + +@@ -1495,19 +1583,12 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { + inotify_rm_watch(j->inotify_fd, m->wd); + } + +- if (j->no_new_files) +- return 0; +- +- FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { +- sd_id128_t id; ++ directory_watch(j, m, dirfd(d), ++ IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE| ++ IN_ONLYDIR); + +- if (dirent_is_file_with_suffix(de, ".journal") || +- dirent_is_file_with_suffix(de, ".journal~")) +- (void) add_file(j, m->path, de->d_name); +- else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) && +- sd_id128_from_string(de->d_name, &id) >= 0) +- (void) add_directory(j, m->path, de->d_name); +- } ++ if (!j->no_new_files) ++ directory_enumerate(j, m, d); + + check_network(j, dirfd(d)); + +@@ -2068,6 +2149,18 @@ _public_ void sd_journal_restart_data(sd_journal *j) { + j->current_field = 0; + } + ++static int reiterate_all_paths(sd_journal *j) { ++ assert(j); ++ ++ if (j->no_new_files) ++ return add_current_paths(j); ++ ++ if (j->path) ++ return add_root_directory(j, j->path, true); ++ ++ return add_search_paths(j); ++} ++ + _public_ int sd_journal_get_fd(sd_journal *j) { + int r; + +@@ -2081,15 +2174,11 @@ _public_ int sd_journal_get_fd(sd_journal *j) { + if (r < 0) + return r; + +- /* Iterate through all dirs again, to add them to the +- * inotify */ +- if (j->no_new_files) +- r = add_current_paths(j); +- else if (j->path) +- r = add_root_directory(j, j->path, true); +- else +- r = add_search_paths(j); +- if (r < 0) ++ log_debug("Reiterating files to get inotify watches established."); ++ ++ /* Iterate through all dirs again, to add them to the inotify */ ++ r = reiterate_all_paths(j); ++ if (r < 0) + return r; + + return j->inotify_fd; +@@ -2131,12 +2220,58 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { + return 1; + } + ++static void process_q_overflow(sd_journal *j) { ++ JournalFile *f; ++ Directory *m; ++ Iterator i; ++ ++ assert(j); ++ ++ /* When the inotify queue overruns we need to enumerate and re-validate all journal files to bring our list ++ * back in sync with what's on disk. For this we pick a new generation counter value. It'll be assigned to all ++ * journal files we encounter. All journal files and all directories that don't carry it after reenumeration ++ * are subject for unloading. */ ++ ++ log_debug("Inotify queue overrun, reiterating everything."); ++ ++ j->generation++; ++ (void) reiterate_all_paths(j); ++ ++ ORDERED_HASHMAP_FOREACH(f, j->files, i) { ++ ++ if (f->last_seen_generation == j->generation) ++ continue; ++ ++ log_debug("File '%s' hasn't been seen in this enumeration, removing.", f->path); ++ remove_file_real(j, f); ++ } ++ ++ HASHMAP_FOREACH(m, j->directories_by_path, i) { ++ ++ if (m->last_seen_generation == j->generation) ++ continue; ++ ++ if (m->is_root) /* Never GC root directories */ ++ continue; ++ ++ log_debug("Directory '%s' hasn't been seen in this enumeration, removing.", f->path); ++ remove_directory(j, m); ++ } ++ ++ log_debug("Reiteration complete."); ++} ++ + static void process_inotify_event(sd_journal *j, struct inotify_event *e) { + Directory *d; + + assert(j); + assert(e); + ++ if (e->mask & IN_Q_OVERFLOW) { ++ process_q_overflow(j); ++ return; ++ } ++ + /* Is this a subdirectory we watch? */ + d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd)); + if (d) { +diff --git a/src/shared/path-util.c b/src/shared/path-util.c +index 5d4de9ec4..fcc591686 100644 +--- a/src/shared/path-util.c ++++ b/src/shared/path-util.c +@@ -861,3 +861,17 @@ char *prefix_root(const char *root, const char *path) { + strcpy(p, path); + return n; + } ++ ++int inotify_add_watch_fd(int fd, int what, uint32_t mask) { ++ char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; ++ int r; ++ ++ /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */ ++ xsprintf(path, "/proc/self/fd/%i", what); ++ ++ r = inotify_add_watch(fd, path, mask); ++ if (r < 0) ++ return -errno; ++ ++ return r; ++} +diff --git a/src/shared/path-util.h b/src/shared/path-util.h +index 34c016229..96490e12b 100644 +--- a/src/shared/path-util.h ++++ b/src/shared/path-util.h +@@ -66,6 +66,8 @@ int fsck_exists(const char *fstype); + + char *prefix_root(const char *root, const char *path); + ++int inotify_add_watch_fd(int fd, int what, uint32_t mask); ++ + /* Similar to prefix_root(), but returns an alloca() buffer, or + * possibly a const pointer into the path parameter */ + #define prefix_roota(root, path) \ diff --git a/SOURCES/0611-sd-journal-make-sure-it-s-safe-to-call-sd_journal_pr.patch b/SOURCES/0611-sd-journal-make-sure-it-s-safe-to-call-sd_journal_pr.patch new file mode 100644 index 0000000..26c212a --- /dev/null +++ b/SOURCES/0611-sd-journal-make-sure-it-s-safe-to-call-sd_journal_pr.patch @@ -0,0 +1,36 @@ +From efd523764efcd39340fb62875716c8c8b79f0de9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 9 Feb 2018 22:38:46 +0100 +Subject: [PATCH] sd-journal: make sure it's safe to call sd_journal_process() + before the first sd_journal_wait() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In that case we have no inotify fd yet, and there's nothing to process +hence. Let's make the call a NOP. + +(Previously, without this change we'd end up trying to read off inotify +fd -1, which is quite a problem... 😢) + +(cherry picked from commit 10c4d6405f74258ea4fac5db4888c1bf49ad5399) + +Related: #1540538 +--- + src/journal/sd-journal.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 9186f5188..e1cde6e1c 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -2329,6 +2329,9 @@ _public_ int sd_journal_process(sd_journal *j) { + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + ++ if (j->inotify_fd < 0) /* We have no inotify fd yet? Then there's noting to process. */ ++ return 0; ++ + j->last_process_usec = now(CLOCK_MONOTONIC); + j->last_invalidate_counter = j->current_invalidate_counter; + diff --git a/SOURCES/0612-journalctl-Periodically-call-sd_journal_process-in-j.patch b/SOURCES/0612-journalctl-Periodically-call-sd_journal_process-in-j.patch new file mode 100644 index 0000000..026f18b --- /dev/null +++ b/SOURCES/0612-journalctl-Periodically-call-sd_journal_process-in-j.patch @@ -0,0 +1,59 @@ +From 98169577b83b45a40105cf58e6cffe0272074817 Mon Sep 17 00:00:00 2001 +From: Peter Portante +Date: Sun, 28 Jan 2018 16:48:04 -0500 +Subject: [PATCH] journalctl: Periodically call sd_journal_process in + journalctl + +If `journalctl` take a long time to process messages, and during that +time journal file rotation occurs, a `journalctl` client will keep +those rotated files open until it calls `sd_journal_process()`, which +typically happens as a result of calling `sd_journal_wait()` below in +the "following" case. By periodically calling `sd_journal_process()` +during the processing loop we shrink the window of time a client +instance has open file descriptors for rotated (deleted) journal +files. + +(Lennart: slightly reworked version, that dropped some of the commenting +which was solved otherwise) + +(cherry picked from commit ec316d199a13d8db3f6550d60e369893de2fb417) + +Related: #1540538 +--- + src/journal/journalctl.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c +index 0be70764e..1e6d0761c 100644 +--- a/src/journal/journalctl.c ++++ b/src/journal/journalctl.c +@@ -67,6 +67,8 @@ + + #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) + ++#define PROCESS_INOTIFY_INTERVAL 1024 /* Every 1,024 messages processed */ ++ + enum { + /* Special values for arg_lines */ + ARG_LINES_DEFAULT = -2, +@@ -2294,6 +2296,20 @@ int main(int argc, char *argv[]) { + goto finish; + + n_shown++; ++ ++ /* If journalctl take a long time to process messages, and during that time journal file ++ * rotation occurs, a journalctl client will keep those rotated files open until it calls ++ * sd_journal_process(), which typically happens as a result of calling sd_journal_wait() below ++ * in the "following" case. By periodically calling sd_journal_process() during the processing ++ * loop we shrink the window of time a client instance has open file descriptors for rotated ++ * (deleted) journal files. */ ++ if ((n_shown % PROCESS_INOTIFY_INTERVAL) == 0) { ++ r = sd_journal_process(j); ++ if (r < 0) { ++ log_error_errno(r, "Failed to process inotify events: %m"); ++ goto finish; ++ } ++ } + } + + if (!arg_follow) { diff --git a/SOURCES/0613-sd-journal-when-picking-up-a-new-file-compare-inode-.patch b/SOURCES/0613-sd-journal-when-picking-up-a-new-file-compare-inode-.patch new file mode 100644 index 0000000..94dca30 --- /dev/null +++ b/SOURCES/0613-sd-journal-when-picking-up-a-new-file-compare-inode-.patch @@ -0,0 +1,77 @@ +From febbc3baae65db64692e3ae2852630c5e324ab43 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Tue, 20 Feb 2018 14:16:15 +0100 +Subject: [PATCH] sd-journal: when picking up a new file, compare inode/device + info with previous open file by same name + +Let's make sure we aren't confused if a journal file is replaced by a +different one (for example due to rotation) if we are in a q overflow: +let's compare the inode/device information, and if it changed replace +any open file object as needed. + +Fixes: #8198 + +(cherry-picked from commit 32cb1983ad6f7084ff86e259ff079742a8139719) + +[msekleta: this is very slimmed down version of the above commit because +a lot of code from is not applicable to RHEL-7 version] + +Related: #1540538 +--- + src/journal/sd-journal.c | 35 +++++++++++++++++++++++++++++------ + 1 file changed, 29 insertions(+), 6 deletions(-) + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index e1cde6e1c..004fe646d 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -1224,20 +1224,43 @@ static bool file_type_wanted(int flags, const char *filename) { + + static int add_any_file(sd_journal *j, const char *path) { + JournalFile *f = NULL; ++ struct stat st; + int r, k; + + assert(j); + assert(path); + +- if (path) { +- f = ordered_hashmap_get(j->files, path); +- if (f) { +- /* Mark this file as seen in this generation. This is used to GC old files in +- * process_q_overflow() to detect journal files that are still and discern them from those who +- * are gone. */ ++ if (stat(path, &st) < 0) { ++ r = log_debug_errno(errno, "Failed to stat file '%s': %m", path); ++ return -errno; ++ } ++ if (S_ISDIR(st.st_mode)) { ++ log_debug("Uh, file '%s' is a directory? Refusing.", path); ++ return -EISDIR; ++ } ++ if (!S_ISREG(st.st_mode)) { ++ log_debug("Uh, file '%s' is not a regular file? Refusing.", path); ++ return -EBADFD; ++ } ++ ++ f = ordered_hashmap_get(j->files, path); ++ if (f) { ++ ++ if (f->last_stat.st_dev == st.st_dev && ++ f->last_stat.st_ino == st.st_ino) { ++ ++ /* We already track this file, under the same path and with the same device/inode numbers, it's hence ++ * really the same. Mark this file as seen in this generation. This is used to GC old files in ++ * process_q_overflow() to detect journal files that are still and discern them from those who are ++ * gone. */ + f->last_seen_generation = j->generation; + return 0; + } ++ ++ /* So we tracked a file under this name, but it has a different inode/device. In that case, it got ++ * replaced (probably due to rotation?), let's drop it hence from our list. */ ++ remove_file_real(j, f); ++ f = NULL; + } + + if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { diff --git a/SOURCES/76-phys-port-name.rules b/SOURCES/76-phys-port-name.rules index 92bb25a..067f73a 100644 --- a/SOURCES/76-phys-port-name.rules +++ b/SOURCES/76-phys-port-name.rules @@ -4,5 +4,6 @@ SUBSYSTEM!="net", GOTO="phys_port_name_end" DRIVERS=="mlxsw*", ATTR{phys_port_name}=="?*", IMPORT{program}="/usr/lib/udev/phys-port-name-gen %k" DRIVERS=="rocker", ATTR{phys_port_name}=="?*", IMPORT{program}="/usr/lib/udev/phys-port-name-gen %k" +DRIVERS=="nfp*", ATTR{phys_port_name}=="?*", IMPORT{program}="/usr/lib/udev/phys-port-name-gen %k" LABEL="phys_port_name_end" diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index a81bb0c..6bdbb74 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: 42%{?dist}.10 +Release: 57%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: A System and Service Manager @@ -537,25 +537,121 @@ Patch0495: 0495-systemd-notify-Always-pass-a-valid-pid-to-sd_pid_not.patch Patch0496: 0496-sd_pid_notify_with_fds-fix-computing-msg_controllen.patch Patch0497: 0497-rules-move-cpu-hotplug-rule-to-separate-file.patch Patch0498: 0498-Revert-rules-move-cpu-hotplug-rule-to-separate-file.patch -Patch0499: 0499-Revert-udev-net_id-add-support-for-phys_port_name-at.patch -Patch0500: 0500-sysctl-fix-uninitialized-variable.patch -Patch0501: 0501-udev-ignore-SIGCHLD-from-unexpected-processes-130653.patch -Patch0502: 0502-manager-when-reexecuting-try-to-connect-to-bus-only-.patch -Patch0503: 0503-unmount-Pass-in-mount-options-when-remounting-read-o.patch -Patch0504: 0504-shutdown-don-t-remount-ro-network-filesystems.-6588.patch -Patch0505: 0505-shutdown-fix-incorrect-fscanf-result-check-6806.patch -Patch0506: 0506-manager-fix-connecting-to-bus-when-dbus-is-actually-.patch -Patch0507: 0507-automount-ack-automount-requests-even-when-already-m.patch -Patch0508: 0508-shared-cgroup-utils-_CGROUP_CONTROLLER_MASK_ALL-does.patch -Patch0509: 0509-core-execute-fix-fork-fail-handling-in-exec_spawn.patch -Patch0510: 0510-journal-remove-error-check-that-never-happens.patch -Patch0511: 0511-sd-journal-various-clean-ups-and-modernizations.patch -Patch0512: 0512-journalctl-continue-operation-even-if-we-run-into-an.patch -Patch0513: 0513-journalctl-when-we-fail-to-open-a-journal-file-print.patch -Patch0514: 0514-sd-journal-properly-handle-inotify-queue-overflow.patch -Patch0515: 0515-sd-journal-make-sure-it-s-safe-to-call-sd_journal_pr.patch -Patch0516: 0516-sd-journal-when-picking-up-a-new-file-compare-inode-.patch -Patch0517: 0517-journalctl-Periodically-call-sd_journal_process-in-j.patch +Patch0499: 0499-tests-use-XFS-as-root-filesystem-for-system-tests.patch +Patch0500: 0500-tests-use-fdisk-instead-of-sfdisk.patch +Patch0501: 0501-Revert-udev-net_id-add-support-for-phys_port_name-at.patch +Patch0502: 0502-core-unset-sysfs-path-after-transition-to-dead-state.patch +Patch0503: 0503-sysctl-fix-uninitialized-variable.patch +Patch0504: 0504-udev-ignore-SIGCHLD-from-unexpected-processes-130653.patch +Patch0505: 0505-compile-with-Werror.patch +Patch0506: 0506-myhostname-don-t-return-any-ipv6-entries-when-ipv6-i.patch +Patch0507: 0507-core-execute-fix-fork-fail-handling-in-exec_spawn.patch +Patch0508: 0508-fix-compilation-after-commit-382877acc6c029e59e359a0.patch +Patch0509: 0509-Redefine-32bit-time_t-format-to-signed.patch +Patch0510: 0510-sd-bus-bus-kernel.c-fix-format-errors-on-ppc64le.patch +Patch0511: 0511-tmpfiles-with-e-don-t-attempt-to-set-permissions-whe.patch +Patch0512: 0512-units-introduce-getty-pre.target-6667.patch +Patch0513: 0513-units-order-container-and-console-getty-units-after-.patch +Patch0514: 0514-log-never-log-into-foreign-fd-2-in-PID-1-or-its-pre-.patch +Patch0515: 0515-nspawn-new-option-to-start-as-PID2.patch +Patch0516: 0516-journal-implicitly-flush-to-var-on-recovery-4028.patch +Patch0517: 0517-journal-add-use-flushed_flag_is_set-helper-4041.patch +Patch0518: 0518-journald-don-t-flush-to-var-log-journal-before-we-ge.patch +Patch0519: 0519-path-util-make-use-of-mnt_id-field-exported-in-proc-.patch +Patch0520: 0520-Revert-Revert-journald-allow-restarting-journald-wit.patch +Patch0521: 0521-journald-make-sure-we-retain-all-stream-fds-across-r.patch +Patch0522: 0522-Allow-systemd-tmpfiles-to-set-the-file-directory-att.patch +Patch0523: 0523-tmpfiles-rework-file-attribute-code.patch +Patch0524: 0524-tmpfiles-warn-if-we-get-an-argument-on-lines-that-do.patch +Patch0525: 0525-tmpfiles-substitute-specifiers-in-arguments-for-writ.patch +Patch0526: 0526-btrfs-util-introduce-btrfs_is_filesystem-and-make-us.patch +Patch0527: 0527-journal-don-t-force-FS_NOCOW_FL-on-new-journal-files.patch +Patch0528: 0528-tmpfiles-Add-C-attrib-to-the-journal-files-directori.patch +Patch0529: 0529-Revert-path-util-make-use-of-mnt_id-field-exported-i.patch +Patch0530: 0530-device-make-sure-to-remove-all-device-units-sharing-.patch +Patch0531: 0531-manager-when-reexecuting-try-to-connect-to-bus-only-.patch +Patch0532: 0532-doc-document-service-exit-codes.patch +Patch0533: 0533-units-order-cryptsetup-pre.target-before-cryptsetup..patch +Patch0534: 0534-man-add-an-explicit-description-of-_netdev-to-system.patch +Patch0535: 0535-units-add-remote-cryptsetup.target-and-remote-crypts.patch +Patch0536: 0536-cryptsetup-generator-use-remote-cryptsetup.target-wh.patch +Patch0537: 0537-Support-rdma-as-a-ListenNetlink-argument-6626.patch +Patch0538: 0538-core-namespace-Protect-usr-instead-of-home-with-Prot.patch +Patch0539: 0539-udev-Use-parent-bus-id-for-virtio-disk-builtin-path-.patch +Patch0540: 0540-socket-util-socket_address_parse-should-not-log-erro.patch +Patch0541: 0541-test-fix-failing-test-socket-util-when-running-with-.patch +Patch0542: 0542-scsi_id-add-missing-options-to-getopt_long-6501.patch +Patch0543: 0543-unmount-Pass-in-mount-options-when-remounting-read-o.patch +Patch0544: 0544-shutdown-don-t-remount-ro-network-filesystems.-6588.patch +Patch0545: 0545-shutdown-fix-incorrect-fscanf-result-check-6806.patch +Patch0546: 0546-path-util-make-use-of-mnt_id-field-exported-in-proc-.patch +Patch0547: 0547-support-ranges-when-parsing-CPUAffinity.patch +Patch0548: 0548-man-Update-man-page-documentation-for-CPUAffinity.patch +Patch0549: 0549-test-path-util-force-rm_rf.patch +Patch0550: 0550-Export-NVMe-WWID-udev-attribute-5348.patch +Patch0551: 0551-mount-make-sure-we-unmount-tmpfs-mounts-before-we-de.patch +Patch0552: 0552-journald-never-accept-fds-from-file-systems-with-man.patch +Patch0553: 0553-udev-builtin-keyboard-move-fetching-the-device-node-.patch +Patch0554: 0554-udev-builtin-keyboard-immediately-EVIOCSKEYCODE-when.patch +Patch0555: 0555-udev-builtin-keyboard-move-actual-key-mapping-to-a-h.patch +Patch0556: 0556-udev-builtin-keyboard-invert-a-condition.patch +Patch0557: 0557-udev-builtin-keyboard-add-support-for-EVDEV_ABS_.patch +Patch0558: 0558-hwdb-sync-60-evdev.hwdb-from-systemd-v235.patch +Patch0559: 0559-journal-ensure-open-journals-from-find_journal-3973.patch +Patch0560: 0560-journal-only-check-available-space-when-journal-is-o.patch +Patch0561: 0561-automount-if-an-automount-unit-is-masked-don-t-react.patch +Patch0562: 0562-units-add-Install-section-to-remote-cryptsetup.targe.patch +Patch0563: 0563-units-replace-remote-cryptsetup-pre.target-with-remo.patch +Patch0564: 0564-man-add-a-note-about-_netdev-usage.patch +Patch0565: 0565-units-make-remote-cryptsetup.target-also-after-crypt.patch +Patch0566: 0566-cryptsetup-generator-use-after-free.patch +Patch0567: 0567-manager-fix-connecting-to-bus-when-dbus-is-actually-.patch +Patch0568: 0568-journal-remote-make-url-option-support-arbitrary-url.patch +Patch0569: 0569-journald-make-maximum-size-of-stream-log-lines-confi.patch +Patch0570: 0570-service-serialize-information-about-currently-execut.patch +Patch0571: 0571-tests-add-new-test-for-issue-518.patch +Patch0572: 0572-tests-in-RHEL-7-we-don-t-have-python3-by-default.patch +Patch0573: 0573-service-attempt-to-execute-next-main-command-only-fo.patch +Patch0574: 0574-timedatectl-stop-using-xstrftime.patch +Patch0575: 0575-Add-support-to-read-lz4-compressed-journals.patch +Patch0576: 0576-journald-never-block-when-sending-messages-on-NOTIFY.patch +Patch0577: 0577-journal-restore-watchdog-support.patch +Patch0578: 0578-cgroup-resource-property-setting-ignored-if-einval.patch +Patch0579: 0579-fileio-add-new-helper-call-read_line-as-bounded-getl.patch +Patch0580: 0580-def-add-new-constant-LONG_LINE_MAX.patch +Patch0581: 0581-fileio-rework-read_one_line_file-on-top-of-read_line.patch +Patch0582: 0582-cgroup-util-replace-one-use-of-fgets-by-read_line.patch +Patch0583: 0583-conf-parse-remove-4K-line-length-limit.patch +Patch0584: 0584-test-conf-parser-add-tests-for-config-parser.patch +Patch0585: 0585-fileio-use-_cleanup_-for-FILE-unlocking.patch +Patch0586: 0586-test-fileio-also-test-read_line-with-actual-files.patch +Patch0587: 0587-fileio-return-0-from-read_one_line_file-on-success.patch +Patch0588: 0588-man-fix-description-of-force-in-halt-8-7392.patch +Patch0589: 0589-journal-return-better-error-for-empty-files.patch +Patch0590: 0590-journalctl-continue-operation-even-if-we-run-into-an.patch +Patch0591: 0591-journal-remove-error-check-that-never-happens.patch +Patch0592: 0592-sd-journal-various-clean-ups-and-modernizations.patch +Patch0593: 0593-journalctl-when-we-fail-to-open-a-journal-file-print.patch +Patch0594: 0594-journald-fix-accuracy-of-watchdog-timer-event.patch +Patch0595: 0595-core-fix-the-reversed-sanity-check-when-setting-Star.patch +Patch0596: 0596-shared-dropin-ignore-ENAMETOOLONG-when-checking-drop.patch +Patch0597: 0597-cryptsetup-when-unlocking-always-put-path-to-the-obj.patch +Patch0598: 0598-cryptsetup-use-more-descriptive-name-for-the-variabl.patch +Patch0599: 0599-cryptsetup-generator-do-not-bind-to-the-decrypted-de.patch +Patch0600: 0600-shared-cgroup-utils-_CGROUP_CONTROLLER_MASK_ALL-does.patch +Patch0601: 0601-automount-ack-automount-requests-even-when-already-m.patch +Patch0602: 0602-udev-net_id-add-support-for-platform-bus-ACPI-mostly.patch +Patch0603: 0603-journald-native-Fix-typo-in-MANDLOCK-message.patch +Patch0604: 0604-process-util-make-our-freeze-routine-do-something-us.patch +Patch0605: 0605-dbus-propagate-errors-from-bus_init_system-and-bus_i.patch +Patch0606: 0606-bus-util.c-fix-TasksMax-property-assignment.patch +Patch0607: 0607-sparse-avoid-clash-with-__bitwise-and-__force-from-4.patch +Patch0608: 0608-core-Let-two-more-booleans-survive-a-daemon-reload.patch +Patch0609: 0609-core-don-t-choke-if-a-unit-another-unit-triggers-van.patch +Patch0610: 0610-sd-journal-properly-handle-inotify-queue-overflow.patch +Patch0611: 0611-sd-journal-make-sure-it-s-safe-to-call-sd_journal_pr.patch +Patch0612: 0612-journalctl-Periodically-call-sd_journal_process-in-j.patch +Patch0613: 0613-sd-journal-when-picking-up-a-new-file-compare-inode-.patch %global num_patches %{lua: c=0; for i,p in ipairs(patches) do c=c+1; end; print(c);} @@ -574,6 +670,7 @@ BuildRequires: libblkid-devel BuildRequires: xz-devel BuildRequires: zlib-devel BuildRequires: bzip2-devel +BuildRequires: lz4-devel BuildRequires: libidn-devel BuildRequires: libcurl-devel BuildRequires: kmod-devel @@ -615,7 +712,7 @@ Provides: /sbin/shutdown Provides: syslog Provides: systemd-units = %{version}-%{release} -Conflicts: dracut < 033-499 +Conflicts: dracut < 033-243 Conflicts: initscripts < 9.49.28-1 #Obsolete packages when we are migrating from rhel6 @@ -764,6 +861,7 @@ CONFIGURE_OPTS=( --enable-compat-libs --disable-sysusers --disable-ldconfig + --enable-lz4 %ifarch s390 s390x ppc %{power64} aarch64 --disable-lto %endif @@ -869,6 +967,8 @@ mkdir -p %{buildroot}%{_localstatedir}/lib/systemd/coredump mkdir -p %{buildroot}%{_localstatedir}/lib/systemd/catalog mkdir -p %{buildroot}%{_localstatedir}/lib/systemd/backlight mkdir -p %{buildroot}%{_localstatedir}/lib/systemd/rfkill +mkdir -p %{buildroot}%{_localstatedir}/lib/systemd/journal-upload + touch %{buildroot}%{_localstatedir}/lib/systemd/catalog/database touch %{buildroot}%{_sysconfdir}/udev/hwdb.bin touch %{buildroot}%{_localstatedir}/lib/systemd/random-seed @@ -1108,7 +1208,7 @@ if [ -z "$preferred" ]; then preferred=kdm fi fi -if [ -n "$preferred" -a -r "/usr/lib/systemd/system/$preferred.service" ]; then +if [ $1 -eq 1 -a -n "$preferred" -a -r "/usr/lib/systemd/system/$preferred.service" ]; then # This is supposed to fail when the symlink already exists ln -s "/usr/lib/systemd/system/$preferred.service" /etc/systemd/system/display-manager.service >/dev/null 2>&1 || : fi @@ -1490,6 +1590,7 @@ fi %{_prefix}/lib/systemd/systemd-journal-upload %{_prefix}/lib/systemd/systemd-journal-remote %{_prefix}/lib/tmpfiles.d/systemd-remote.conf +%dir %attr(0755,systemd-journal-upload,systemd-journal-upload) %{_localstatedir}/lib/systemd/journal-upload %{_mandir}/man8/systemd-journal-gatewayd.* %{_mandir}/man8/systemd-journal-remote.* %{_datadir}/systemd/gatewayd @@ -1524,43 +1625,154 @@ fi %{_mandir}/man8/systemd-resolved.* %changelog -* Wed Feb 21 2018 Lukas Nykryn - 219-42.10 -- journal: remove error check that never happens (#1465759) -- sd-journal: various clean-ups and modernizations (#1465759) -- journalctl: continue operation, even if we run into an invalid file (#1465759) -- journalctl: when we fail to open a journal file, print why (#1465759) +* Tue Feb 20 2018 Lukas Nykryn - 219-57 - sd-journal: properly handle inotify queue overflow (#1540538) - sd-journal: make sure it's safe to call sd_journal_process() before the first sd_journal_wait() (#1540538) -- sd-journal: when picking up a new file, compare inode/device info with previous open file by same name (#1540538) - journalctl: Periodically call sd_journal_process in journalctl (#1540538) +- sd-journal: when picking up a new file, compare inode/device info with previous open file by same name (#1540538) -* Mon Feb 19 2018 Lukas Nykryn - 219-42.9 -- core:execute: fix fork() fail handling in exec_spawn() (#1437114) +* Mon Feb 19 2018 Lukas Nykryn - 219-56 +- core: don't choke if a unit another unit triggers vanishes during reload (#1545676) -* Tue Feb 13 2018 Lukas Nykryn - 219-42.8 -- shared/cgroup-utils: _CGROUP_CONTROLLER_MASK_ALL does not cover CGROUP_PIDS (#1532586) +* Wed Feb 07 2018 Lukas Nykryn - 219-55 +- sparse: avoid clash with __bitwise and __force from 4.10 linux/types.h (#5061) (#1447937) +- core: Let two more booleans survive a daemon-reload (#1542391) -* Wed Jan 17 2018 Lukas Nykryn - 219-42.7 +* Tue Feb 06 2018 Lukas Nykryn - 219-54 - automount: ack automount requests even when already mounted (#1535135) +- udev: net_id add support for platform bus (ACPI, mostly arm64) devices (#1529633) +- journald-native: Fix typo in MANDLOCK message (#1501017) +- process-util: make our freeze() routine do something useful (#1540941) +- dbus: propagate errors from bus_init_system() and bus_init_api() (#1541061) +- bus-util.c: fix TasksMax= property assignment (#1537147) -* Tue Jan 09 2018 Lukas Nykryn - 219-42.6 -- manager: fix connecting to bus when dbus is actually around (#7205) (#1465737) +* Tue Jan 09 2018 Lukas Nykryn - 219-53 +- shared/cgroup-utils: _CGROUP_CONTROLLER_MASK_ALL does not cover CGROUP_PIDS (#1532586) + +* Thu Dec 14 2017 Lukas Nykryn - 219-52 +- cryptsetup: when unlocking always put path to the object into Id (#1511043) +- cryptsetup: use more descriptive name for the variable and drop redundant function (#1511043) +- cryptsetup-generator: do not bind to the decrypted device unit (#6538) (#1511043) +- introduce naming based on phys_port_name for nfp via udev rule (#1516283) + +* Tue Dec 05 2017 Lukáš Nykrýn - 219-51 +- revert substitute PACKAGE_STRING with the actual package NVR (#1453153) + +* Mon Dec 04 2017 Lukas Nykryn - 219-50 +- core: fix the reversed sanity check when setting StartupBlockIOWeight over dbus (#1302305) +- shared/dropin: ignore ENAMETOOLONG when checking drop-in directories (#7525) (#1489095) +- enable display manager only on systemd installation (#1464893) +- remove unnecessary dependency on dracut (#1466676) +- substitute PACKAGE_STRING with the actual package NVR (#1453153) + +* Fri Nov 24 2017 Lukas Nykryn - 219-49 +- journald: fix accuracy of watchdog timer event (#1511565) + +* Thu Nov 23 2017 Lukas Nykryn - 219-48 +- journald: never block when sending messages on NOTIFY_SOCKET socket (#1511565) +- journal: restore watchdog support (#1511565) +- cgroup resource property setting ignored if einval (rhbz#1302305) +- fileio: add new helper call read_line() as bounded getline() replacement (#1503106) +- def: add new constant LONG_LINE_MAX (#1503106) +- fileio: rework read_one_line_file() on top of read_line() (#1503106) +- cgroup-util: replace one use of fgets() by read_line() (#1503106) +- conf-parse: remove 4K line length limit (#1503106) +- test-conf-parser: add tests for config parser (#1503106) +- fileio: use _cleanup_ for FILE unlocking (#1503106) +- test-fileio: also test read_line() with actual files (#1503106) +- fileio: return 0 from read_one_line_file on success (#1503106) +- man: fix description of --force in halt(8) (#7392) (#1515130) +- journal: return better error for empty files (#1465759) +- journalctl: continue operation, even if we run into an invalid file (#1465759) +- journal: remove error check that never happens (#1465759) +- sd-journal: various clean-ups and modernizations (#1465759) +- journalctl: when we fail to open a journal file, print why (#1465759) -* Thu Dec 07 2017 Lukas Nykryn - 219-42.5 +* Thu Nov 16 2017 Lukas Nykryn - 219-47 +- cryptsetup-generator: use after free (#1477757) +- manager: fix connecting to bus when dbus is actually around (#7205) (#1465737) +- journal-remote: make --url option support arbitrary url (#1505385) +- journald: make maximum size of stream log lines configurable and bump it to 48K (#6838) (#1442262) +- service: serialize information about currently executing command (#1404657,#1471230) +- tests: add new test for issue #518 (#1404657,) +- tests: in RHEL-7 we don't have python3 by default (#1404657,) +- service: attempt to execute next main command only for oneshot services (#6619) (#1404657,) +- timedatectl: stop using xstrftime (#1503942) +- Add support to read lz4 compressed journals (rhbz#1431687) + +* Tue Oct 31 2017 Lukas Nykryn - 219-46 +- Support 'rdma' as a ListenNetlink= argument (#6626) (#1494610) +- core/namespace: Protect /usr instead of /home with ProtectSystem=yes (#1493047) +- udev: Use parent bus id for virtio disk builtin path-id (#5500) (#1496697) +- socket-util: socket_address_parse() should not log errors on its own (#1497639) +- test: fix failing test-socket-util when running with ipv6.disable=1 kernel param (#1497639) +- scsi_id: add missing options to getopt_long() (#6501) (#1476910) - unmount: Pass in mount options when remounting read-only (#1312002) - shutdown: don't remount,ro network filesystems. (#6588) (#1312002) - shutdown: fix incorrect fscanf() result check (#6806) (#1312002) - -* Fri Sep 29 2017 Lukas Nykryn - 219-42.4 +- path-util: make use of "mnt_id" field exported in /proc/self/fdinfo/ (#1472439) +- support ranges when parsing CPUAffinity (#1493976) +- man: Update man page documentation for CPUAffinity (#1493976) +- test-path-util: force rm_rf (#1472439) +- Export NVMe WWID udev attribute (#5348) (#1503253) +- mount: make sure we unmount tmpfs mounts before we deactivate swaps (#7076) (#1437518) +- journald: never accept fds from file systems with mandatory locking enabled (#1501017) +- udev: builtin-keyboard: move fetching the device node up (#1500119) +- udev: builtin-keyboard: immediately EVIOCSKEYCODE when we have a pair (#1500119) +- udev: builtin-keyboard: move actual key mapping to a helper function (#1500119) +- udev: builtin-keyboard: invert a condition (#1500119) +- udev: builtin-keyboard: add support for EVDEV_ABS_* (#1500119) +- hwdb: sync 60-evdev.hwdb from systemd v235 (rhbz#1500119) +- journal: ensure open journals from find_journal() (#3973) (#1493846) +- journal: only check available space when journal is open (#1493846) +- automount: if an automount unit is masked, don't react to activation anymore (#5445) (#1498318) +- units: add [Install] section to remote-cryptsetup.target (#1477757) +- units: replace remote-cryptsetup-pre.target with remote-fs-pre.target (#1477757) +- man: add a note about _netdev usage (#1477757) +- units: make remote-cryptsetup.target also after cryptsetup-pre.target (#1477757) + +* Wed Sep 27 2017 Lukas Nykryn - 219-45 +- journal: implicitly flush to var on recovery (#4028) (#1364092) +- journal: add/use flushed_flag_is_set() helper (#4041) (#1364092) +- journald: don't flush to /var/log/journal before we get asked to (#1364092) +- path-util: make use of "mnt_id" field exported in /proc/self/fdinfo/ (#1472439) +- Revert "Revert "journald: allow restarting journald without losing stream connections"" (#1359939) +- journald: make sure we retain all stream fds across restarts (#6348) (#1359939) +- Allow systemd-tmpfiles to set the file/directory attributes (#1299714) +- tmpfiles: rework file attribute code (#1299714) +- tmpfiles: warn if we get an argument on lines that don't take any (#1299714) +- tmpfiles: substitute % specifiers in arguments for writing files and xattrs (#1299714) +- btrfs-util: introduce btrfs_is_filesystem() and make use of it where appropriate (#1299714) +- journal: don't force FS_NOCOW_FL on new journal files, but warn if it is missing (#1299714) +- tmpfiles: Add +C attrib to the journal files directories (#1299714) +- Revert "path-util: make use of "mnt_id" field exported in /proc/self/fdinfo/" (#1472439) +- device: make sure to remove all device units sharing the same sysfs path (#6679) (#1408916) - manager: when reexecuting try to connect to bus only when dbus.service is around (#6773) (#1465737) - -* Mon Sep 25 2017 Lukas Nykryn - 219-42.3 -- udev: ignore SIGCHLD from unexpected processes (#1306539) (#1306539) - -* Thu Sep 21 2017 Lukas Nykryn - 219-42.2 +- doc: document service exit codes (#1178929) +- units: order cryptsetup-pre.target before cryptsetup.target (#1384014) +- man: add an explicit description of _netdev to systemd.mount(5) (#1384014) +- units: add remote-cryptsetup.target and remote-cryptsetup-pre.target (#1384014) +- cryptsetup-generator: use remote-cryptsetup.target when _netdev is present (#1384014) + +* Tue Sep 12 2017 Lukas Nykryn - 219-44 +- core: unset sysfs path after transition to dead state (#1408916) - sysctl: fix uninitialized variable (#1485121) - -* Tue Aug 15 2017 Lukas Nykryn - 219-42.1 +- udev: ignore SIGCHLD from unexpected processes (#1306539) (#1306539) +- compile with -Werror (#1447937) +- myhostname: don't return any ipv6 entries when ipv6 is disabled (#1444824) +- core:execute: fix fork() fail handling in exec_spawn() (#1437114) +- fix compilation after commit 382877acc6c029e59e359a076d203ca03b4b9e9e (#1447937) +- Redefine 32bit time_t format to signed (#1447937) +- sd-bus/bus-kernel.c: fix format errors on ppc64le (#1447937) +- tmpfiles: with "e" don't attempt to set permissions when file doesn't exist (#1445732) +- units: introduce getty-pre.target (#6667) (#1173080) +- units: order container and console getty units after getty-pre.target (#1173080) +- log: never log into foreign fd #2 in PID 1 or its pre-execve() children (#1420505) +- nspawn: new option to start as PID2 (#1417387) + +* Wed Aug 16 2017 Lukas Nykryn - 219-43 +- tests: use XFS as root filesystem for system tests (#1475870) +- tests: use fdisk instead of sfdisk (#1475870) - Revert "udev: net_id: add support for phys_port_name attribute (#4506)" (#1477285) - reintroduce naming based on phys_port_name for mlxsw and rocker via udev rule